From 7904c0d94aa217584ed292a682cb706ee317a32e Mon Sep 17 00:00:00 2001 From: tstuefe Date: Tue, 12 Aug 2025 08:56:13 +0200 Subject: [PATCH 01/21] Linux query_process_info --- src/hotspot/os/linux/os_linux.cpp | 44 +++++++++++++++++++------------ src/hotspot/os/linux/os_linux.hpp | 11 +++++--- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 4d6225cf21ed2..875688d47cd24 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -351,8 +351,8 @@ julong os::physical_memory() { size_t os::rss() { size_t size = 0; - os::Linux::meminfo_t info; - if (os::Linux::query_process_memory_info(&info)) { + os::Linux::process_info_t info; + if (os::Linux::query_process_info(&info)) { size = info.vmrss * K; } return size; @@ -2313,13 +2313,14 @@ void os::Linux::print_system_memory_info(outputStream* st) { "/sys/kernel/mm/transparent_hugepage/defrag", st); } -bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { +bool os::Linux::query_process_info(os::Linux::process_info_t* info) { FILE* f = os::fopen("/proc/self/status", "r"); - const int num_values = sizeof(os::Linux::meminfo_t) / sizeof(size_t); - int num_found = 0; char buf[256]; info->vmsize = info->vmpeak = info->vmrss = info->vmhwm = info->vmswap = - info->rssanon = info->rssfile = info->rssshmem = -1; + info->rssanon = info->rssfile = info->rssshmem = info->vmpte = -1; + info->threads = info->fdsize = -1; + constexpr int num_values = 11; + int num_found = 0; if (f != nullptr) { while (::fgets(buf, sizeof(buf), f) != nullptr && num_found < num_values) { if ( (info->vmsize == -1 && sscanf(buf, "VmSize: %zd kB", &info->vmsize) == 1) || @@ -2329,7 +2330,10 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { (info->vmrss == -1 && sscanf(buf, "VmRSS: %zd kB", &info->vmrss) == 1) || (info->rssanon == -1 && sscanf(buf, "RssAnon: %zd kB", &info->rssanon) == 1) || // Needs Linux 4.5 (info->rssfile == -1 && sscanf(buf, "RssFile: %zd kB", &info->rssfile) == 1) || // Needs Linux 4.5 - (info->rssshmem == -1 && sscanf(buf, "RssShmem: %zd kB", &info->rssshmem) == 1) // Needs Linux 4.5 + (info->rssshmem == -1 && sscanf(buf, "RssShmem: %zd kB", &info->rssshmem) == 1) || // Needs Linux 4.5 + (info->vmpte == -1 && sscanf(buf, "VmPTE: %zd kB", &info->vmpte) == 1) || // Needs Linux 2.6.10 + (info->fdsize == -1 && sscanf(buf, "FDSize: %d", &info->fdsize) == 1) || + (info->threads == -1 && sscanf(buf, "Threads: %d", &info->threads) == 1) ) { num_found ++; @@ -2375,8 +2379,8 @@ void os::Linux::print_process_memory_info(outputStream* st) { // Print virtual and resident set size; peak values; swap; and for // rss its components if the kernel is recent enough. - meminfo_t info; - if (query_process_memory_info(&info)) { + process_info_t info; + if (query_process_info(&info)) { st->print_cr("Virtual Size: %zdK (peak: %zdK)", info.vmsize, info.vmpeak); st->print("Resident Set Size: %zdK (peak: %zdK)", info.vmrss, info.vmhwm); if (info.rssanon != -1) { // requires kernel >= 4.5 @@ -2661,8 +2665,8 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { #if INCLUDE_JFR void os::jfr_report_memory_info() { - os::Linux::meminfo_t info; - if (os::Linux::query_process_memory_info(&info)) { + os::Linux::process_info_t info; + if (os::Linux::query_process_info(&info)) { // Send the RSS JFR event EventResidentSetSize event; event.set_size(info.vmrss * K); @@ -4872,8 +4876,9 @@ int os::open(const char *path, int oflag, int mode) { // All file descriptors that are opened in the Java process and not // specifically destined for a subprocess should have the close-on-exec // flag set. If we don't set it, then careless 3rd party native code - // might fork and exec without closing all appropriate file descriptors, - // and this in turn might: + // might fork and exec without closing all appropriate file descriptors + // (e.g. as we do in closeDescriptors in UNIXProcess.c), and this in + // turn might: // // - cause end-of-file to fail to be detected on some file // descriptors, resulting in mysterious hangs, or @@ -5308,6 +5313,7 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) { } #ifdef __GLIBC__ +static unsigned g_num_trims = 0; void os::Linux::get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped) { if (g_mallinfo2) { new_mallinfo mi = g_mallinfo2(); @@ -5321,6 +5327,7 @@ void os::Linux::get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped) { out->uordblks = mi.uordblks; out->fordblks = mi.fordblks; out->keepcost = mi.keepcost; + out->num_trims = g_num_trims; *might_have_wrapped = false; } else if (g_mallinfo) { old_mallinfo mi = g_mallinfo(); @@ -5335,6 +5342,7 @@ void os::Linux::get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped) { out->uordblks = (size_t)(unsigned)mi.uordblks; out->fordblks = (size_t)(unsigned)mi.fordblks; out->keepcost = (size_t)(unsigned)mi.keepcost; + out->num_trims = g_num_trims; *might_have_wrapped = NOT_LP64(false) LP64_ONLY(true); } else { // We should have either mallinfo or mallinfo2 @@ -5352,14 +5360,14 @@ int os::Linux::malloc_info(FILE* stream) { bool os::trim_native_heap(os::size_change_t* rss_change) { #ifdef __GLIBC__ - os::Linux::meminfo_t info1; - os::Linux::meminfo_t info2; + os::Linux::process_info_t info1; + os::Linux::process_info_t info2; bool have_info1 = rss_change != nullptr && - os::Linux::query_process_memory_info(&info1); + os::Linux::query_process_info(&info1); ::malloc_trim(0); bool have_info2 = rss_change != nullptr && have_info1 && - os::Linux::query_process_memory_info(&info2); + os::Linux::query_process_info(&info2); ssize_t delta = (ssize_t) -1; if (rss_change != nullptr) { if (have_info1 && have_info2 && @@ -5373,6 +5381,8 @@ bool os::trim_native_heap(os::size_change_t* rss_change) { } } + g_num_trims ++; + return true; #else return false; // musl diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index bd2e1ea323048..c96d0e5966513 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -164,8 +164,9 @@ class os::Linux { // Return the namespace pid if so, otherwise -1. static int get_namespace_pid(int vmid); - // Output structure for query_process_memory_info() (all values in KB) - struct meminfo_t { + // Output structure for query_process_memory_info() + // (memory values in KB) + struct process_info_t { ssize_t vmsize; // current virtual size ssize_t vmpeak; // peak virtual size ssize_t vmrss; // current resident set size @@ -174,12 +175,15 @@ class os::Linux { ssize_t rssanon; // resident set size (anonymous mappings, needs 4.5) ssize_t rssfile; // resident set size (file mappings, needs 4.5) ssize_t rssshmem; // resident set size (shared mappings, needs 4.5) + ssize_t vmpte; // size of page table entries (needs 2.6.10) + int threads; // number of threads + int fdsize; // number of file descriptors }; // Attempts to query memory information about the current process and return it in the output structure. // May fail (returns false) or succeed (returns true) but not all output fields are available; unavailable // fields will contain -1. - static bool query_process_memory_info(meminfo_t* info); + static bool query_process_info(process_info_t* info); // Tells if the user asked for transparent huge pages. static bool _thp_requested; @@ -452,6 +456,7 @@ class os::Linux { size_t uordblks; size_t fordblks; size_t keepcost; + unsigned num_trims; // Number of times the hotspot trimmed by calling os::trim_native_heap. }; static void get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped); From 072becf54311e54b4fc898ca94ddce310713984f Mon Sep 17 00:00:00 2001 From: tstuefe Date: Tue, 12 Aug 2025 09:19:46 +0200 Subject: [PATCH 02/21] xml --- src/hotspot/share/jfr/metadata/metadata.xml | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 42d99e2477de2..0ee8f0dcb9862 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -768,9 +768,12 @@ + description="Total native memory usage for the JVM. Might not be the exact sum of the NativeMemoryUsage events due to timing." period="everyChunk"> + + + + + + + + + + + + + + + + + + + + @@ -1578,5 +1598,4 @@ - From 489e245462f312ce310459dd28b16ac7d2549306 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Tue, 12 Aug 2025 10:27:43 +0200 Subject: [PATCH 03/21] wip --- src/hotspot/os/linux/os_linux.cpp | 46 +++++++++++++++++++ src/hotspot/os/linux/os_linux.hpp | 2 +- src/hotspot/share/jfr/metadata/metadata.xml | 1 + .../share/jfr/periodic/jfrPeriodic.cpp | 9 ++++ src/hotspot/share/runtime/os.hpp | 7 +++ 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 875688d47cd24..d4939d8ff0cc4 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2682,6 +2682,52 @@ void os::jfr_report_memory_info() { } } +void os::jfr_report_process_size() { + os::Linux::process_info_t info; + if (os::Linux::query_process_info(&info)) { + EventProcessSize e; + e.set_vsize(info.vmsize * K); + e.set_rss(info.vmrss * K); + e.set_rssPeak(info.vmhwm * K); + e.set_rssAnon(info.rssanon * K); + e.set_rssFile(info.rssfile * K); + e.set_rssShmem(info.rssshmem * K); + e.set_swap(info.vmswap * K); + + size_t malloc_outstanding = 0; + size_t malloc_retained = 0; +#ifdef __GLIBC__ + bool might_have_wrapped = false; + os::Linux::glibc_mallinfo mi; + os::Linux::get_mallinfo(&mi, &might_have_wrapped); + if (!might_have_wrapped) { + malloc_outstanding = mi.uordblks + mi.hblkhd; + malloc_retained = mi.fordblks; + } +#endif + e.set_libcMallocOutstanding(malloc_outstanding); + e.set_libcMallocRetention(malloc_retained); + e.commit(); + } +} + +void os::jfr_report_openfds() { + os::Linux::process_info_t info; + if (os::Linux::query_process_info(&info)) { + EventOpenFDs e; + e.set_value(info.fdsize); + e.commit(); + } +} + +int os::num_process_threads() { + os::Linux::process_info_t info; + if (os::Linux::query_process_info(&info)) { + return info.threads; + } + return -1; +} + #endif // INCLUDE_JFR #if defined(AMD64) || defined(IA32) || defined(X32) diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index c96d0e5966513..b652dda548692 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -177,7 +177,7 @@ class os::Linux { ssize_t rssshmem; // resident set size (shared mappings, needs 4.5) ssize_t vmpte; // size of page table entries (needs 2.6.10) int threads; // number of threads - int fdsize; // number of file descriptors + int fdsize; // file descriptor array size }; // Attempts to query memory information about the current process and return it in the output structure. diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 0ee8f0dcb9862..d7626cae29fd7 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -887,6 +887,7 @@ + diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0be1c32728c08..ebb4bcc853774 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -99,6 +99,14 @@ TRACE_REQUEST_FUNC(ResidentSetSize) { os::jfr_report_memory_info(); } +TRACE_REQUEST_FUNC(ProcessSize) { + os::jfr_report_process_size(); +} + +TRACE_REQUEST_FUNC(OpenFDs) { + os::jfr_report_openfds(); +} + TRACE_REQUEST_FUNC(JVMInformation) { ResourceMark rm; EventJVMInformation event; @@ -544,6 +552,7 @@ TRACE_REQUEST_FUNC(SwapSpace) { TRACE_REQUEST_FUNC(JavaThreadStatistics) { EventJavaThreadStatistics event; + event.set_osThreadCount(os::num_process_threads()); event.set_activeCount(ThreadService::get_live_thread_count()); event.set_daemonCount(ThreadService::get_daemon_thread_count()); event.set_accumulatedCount(ThreadService::get_total_thread_count()); diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index c34bf77e3d61a..d22d825074af9 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -849,6 +849,13 @@ class os: AllStatic { // Send JFR memory info event static void jfr_report_memory_info() NOT_JFR_RETURN(); + static void jfr_report_process_size() NOT_JFR_RETURN(); + static void jfr_report_openfds() NOT_JFR_RETURN(); + + // Returns number of OS threads for the calling process; -1 if the information cannot be obtained. + // Note: this includes, but is not limited to, the number of threads the JVM has created or that + // are attached to it. It may be higher if many threads are created outside the JVM. + static int num_process_threads(); // Replacement for strerror(). // Will return the english description of the error (e.g. "File not found", as From 18e33b600590d91698ce4ede23fb69072ed6260e Mon Sep 17 00:00:00 2001 From: tstuefe Date: Tue, 12 Aug 2025 14:00:13 +0200 Subject: [PATCH 04/21] wip --- src/hotspot/os/linux/os_linux.cpp | 3 ++ .../jfr/periodic/jfrNativeMemoryEvent.cpp | 3 ++ src/hotspot/share/nmt/mallocTracker.hpp | 31 +++++++++++++++++++ src/hotspot/share/nmt/nmtUsage.cpp | 3 +- src/hotspot/share/nmt/nmtUsage.hpp | 5 +++ src/jdk.jfr/share/conf/jfr/profile.jfc | 10 ++++++ 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index d4939d8ff0cc4..6b003647353c7 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2696,6 +2696,7 @@ void os::jfr_report_process_size() { size_t malloc_outstanding = 0; size_t malloc_retained = 0; + unsigned num_trims = 0; #ifdef __GLIBC__ bool might_have_wrapped = false; os::Linux::glibc_mallinfo mi; @@ -2703,10 +2704,12 @@ void os::jfr_report_process_size() { if (!might_have_wrapped) { malloc_outstanding = mi.uordblks + mi.hblkhd; malloc_retained = mi.fordblks; + num_trims = mi.num_trims; } #endif e.set_libcMallocOutstanding(malloc_outstanding); e.set_libcMallocRetention(malloc_retained); + e.set_libcTrims(num_trims); e.commit(); } } diff --git a/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp b/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp index 875db3773005f..53f8522b97a4f 100644 --- a/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp @@ -59,6 +59,9 @@ void JfrNativeMemoryEvent::send_total_event(const Ticks& timestamp) { event.set_starttime(timestamp); event.set_reserved(usage->total_reserved()); event.set_committed(usage->total_committed()); + event.set_mallocOutstanding(usage->malloc_total()); + event.set_mallocPeak(usage->malloc_peak()); + event.set_mallocUnsafe(usage->malloc_unsafe()); event.commit(); } diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index e71c9374d4b58..651ca170dbc38 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -168,6 +168,11 @@ class MallocMemorySnapshot { return _all_mallocs.count() * MallocHeader::malloc_overhead(); } + size_t malloc_size(MemTag mem_tag) const { + const MallocMemory* mm = by_tag(mem_tag); + return mm->malloc_size() + mm->arena_size(); + } + // Total malloc invocation count size_t total_count() const { return _all_mallocs.count(); @@ -258,6 +263,18 @@ class MallocMemorySummary : AllStatic { // either global or the category limit static inline bool check_exceeds_limit(size_t s, MemTag mem_tag); + // Total malloc'd memory amount + static size_t total() { + return as_snapshot()->total(); + } + + static size_t total_peak_malloc() { + return as_snapshot()->total_peak(); + } + + static size_t malloc_size(MemTag mem_tag) { + return as_snapshot()->malloc_size(mem_tag); + } }; // Main class called from MemTracker to track malloc activities @@ -319,6 +336,20 @@ class MallocTracker : AllStatic { assert(memblock != nullptr, "null pointer"); return (const MallocHeader*)memblock -1; } + + // Total malloc'd memory amount + static size_t total_malloc() { + return MallocMemorySummary::total(); + } + + // Total malloc'd memory amount + static size_t total_peak_malloc() { + return MallocMemorySummary::total_peak_malloc(); + } + + static size_t malloc_size(MemTag mem_tag) { + return MallocMemorySummary::malloc_size(mem_tag); + } }; #endif // SHARE_NMT_MALLOCTRACKER_HPP diff --git a/src/hotspot/share/nmt/nmtUsage.cpp b/src/hotspot/share/nmt/nmtUsage.cpp index 0d2aa40ea07e9..e35b3dbadbde9 100644 --- a/src/hotspot/share/nmt/nmtUsage.cpp +++ b/src/hotspot/share/nmt/nmtUsage.cpp @@ -37,7 +37,8 @@ const NMTUsageOptions NMTUsage::OptionsNoTS = { false, true, true }; NMTUsage::NMTUsage(NMTUsageOptions options) : _malloc_by_type(), - _malloc_total(), + _malloc_total(0), + _malloc_peak(0), _vm_by_type(), _vm_total(), _usage_options(options) { } diff --git a/src/hotspot/share/nmt/nmtUsage.hpp b/src/hotspot/share/nmt/nmtUsage.hpp index 2011e7ed240f5..2e25ca9875e96 100644 --- a/src/hotspot/share/nmt/nmtUsage.hpp +++ b/src/hotspot/share/nmt/nmtUsage.hpp @@ -44,6 +44,7 @@ class NMTUsage : public CHeapObj { private: size_t _malloc_by_type[mt_number_of_tags]; size_t _malloc_total; + size_t _malloc_peak; NMTUsagePair _vm_by_type[mt_number_of_tags]; NMTUsagePair _vm_total; @@ -64,6 +65,10 @@ class NMTUsage : public CHeapObj { size_t total_committed() const; size_t reserved(MemTag mem_tag) const; size_t committed(MemTag mem_tag) const; + + size_t malloc_total() const { return _malloc_total; } + size_t malloc_peak() const { return _malloc_peak; } + size_t malloc_unsafe() const { return _malloc_by_type[(int)mtOther]; } }; #endif // SHARE_NMT_NMTUSAGE_HPP diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 5ffdc8d9e4dbf..2bff0bec00513 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -965,6 +965,16 @@ forRemoval + + true + 5000 ms + + + + true + 1000 ms + + From 09ff5b6979c14e5cc5a949e36f9f2474c7468252 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Wed, 13 Aug 2025 11:30:04 +0200 Subject: [PATCH 05/21] wip --- src/hotspot/os/aix/os_aix.cpp | 3 + src/hotspot/os/bsd/os_bsd.cpp | 4 ++ src/hotspot/os/linux/os_linux.cpp | 59 +++++++++---------- src/hotspot/os/windows/os_windows.cpp | 4 ++ src/hotspot/share/jfr/metadata/metadata.xml | 15 ++--- .../jfr/periodic/jfrNativeMemoryEvent.cpp | 3 - .../share/jfr/periodic/jfrPeriodic.cpp | 4 +- src/hotspot/share/runtime/os.hpp | 2 +- src/jdk.jfr/share/conf/jfr/profile.jfc | 6 +- 9 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 25a930dc1d92d..048e847c8f8fa 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2716,5 +2716,8 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} #if INCLUDE_JFR void os::jfr_report_memory_info() {} +void os::jfr_report_process_size() {} +void os::jfr_report_libc_statistics() {} +int os::num_process_threads() { return -1; } #endif // INCLUDE_JFR diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b7b88e8e606b4..35c4c9ba73b3b 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2473,6 +2473,10 @@ void os::jfr_report_memory_info() { #endif // __APPLE__ } +void os::jfr_report_process_size() {} +void os::jfr_report_libc_statistics() {} +int os::num_process_threads() { return -1; } + #endif // INCLUDE_JFR bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 6b003647353c7..56807f98f71fa 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2664,6 +2664,14 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { #if INCLUDE_JFR +#define JFR_WARN_ONCE(text) { \ + static bool first_warning = true; \ + if (first_warning) { \ + log_warning(jfr)(text); \ + first_warning = false; \ + } \ +} + void os::jfr_report_memory_info() { os::Linux::process_info_t info; if (os::Linux::query_process_info(&info)) { @@ -2673,12 +2681,7 @@ void os::jfr_report_memory_info() { event.set_peak(info.vmhwm * K); event.commit(); } else { - // Log a warning - static bool first_warning = true; - if (first_warning) { - log_warning(jfr)("Error fetching RSS values: query_process_memory_info failed"); - first_warning = false; - } + JFR_WARN_ONCE("Error fetching RSS values: query_process_memory_info failed"); } } @@ -2692,47 +2695,41 @@ void os::jfr_report_process_size() { e.set_rssAnon(info.rssanon * K); e.set_rssFile(info.rssfile * K); e.set_rssShmem(info.rssshmem * K); + e.set_pagetable(info.vmpte * K); e.set_swap(info.vmswap * K); - - size_t malloc_outstanding = 0; - size_t malloc_retained = 0; - unsigned num_trims = 0; -#ifdef __GLIBC__ - bool might_have_wrapped = false; - os::Linux::glibc_mallinfo mi; - os::Linux::get_mallinfo(&mi, &might_have_wrapped); - if (!might_have_wrapped) { - malloc_outstanding = mi.uordblks + mi.hblkhd; - malloc_retained = mi.fordblks; - num_trims = mi.num_trims; - } -#endif - e.set_libcMallocOutstanding(malloc_outstanding); - e.set_libcMallocRetention(malloc_retained); - e.set_libcTrims(num_trims); e.commit(); + } else { + JFR_WARN_ONCE("Error fetching ProcessSize: query_process_memory_info failed"); } } -void os::jfr_report_openfds() { - os::Linux::process_info_t info; - if (os::Linux::query_process_info(&info)) { - EventOpenFDs e; - e.set_value(info.fdsize); +void os::jfr_report_libc_statistics() { +#ifdef __GLIBC__ + bool might_have_wrapped = false; + os::Linux::glibc_mallinfo mi; + os::Linux::get_mallinfo(&mi, &might_have_wrapped); + if (!might_have_wrapped) { + EventLibcStatistics e; + e.set_mallocOutstanding(mi.uordblks + mi.hblkhd); + e.set_mallocRetained(mi.fordblks); + e.set_trims(mi.num_trims); e.commit(); + } else { + JFR_WARN_ONCE("Error libc statistics: too old glibc"); } +#endif } +#endif // INCLUDE_JFR + int os::num_process_threads() { os::Linux::process_info_t info; if (os::Linux::query_process_info(&info)) { - return info.threads; + return info.threads; // These are OS threads } return -1; } -#endif // INCLUDE_JFR - #if defined(AMD64) || defined(IA32) || defined(X32) const char* search_string = "model name"; #elif defined(M68K) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index ffa22bd036540..96db1340f79eb 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -6237,6 +6237,10 @@ void os::jfr_report_memory_info() { } } +void os::jfr_report_process_size() {} +void os::jfr_report_libc_statistics() {} +int os::num_process_threads() { return -1; } + #endif // INCLUDE_JFR diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index d7626cae29fd7..47f6213e5c026 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -771,9 +771,6 @@ description="Total native memory usage for the JVM. Might not be the exact sum of the NativeMemoryUsage events due to timing." period="everyChunk"> - - - - - - + - - - + + + + + diff --git a/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp b/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp index 53f8522b97a4f..875db3773005f 100644 --- a/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNativeMemoryEvent.cpp @@ -59,9 +59,6 @@ void JfrNativeMemoryEvent::send_total_event(const Ticks& timestamp) { event.set_starttime(timestamp); event.set_reserved(usage->total_reserved()); event.set_committed(usage->total_committed()); - event.set_mallocOutstanding(usage->malloc_total()); - event.set_mallocPeak(usage->malloc_peak()); - event.set_mallocUnsafe(usage->malloc_unsafe()); event.commit(); } diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index ebb4bcc853774..ce3c5656f18be 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -103,8 +103,8 @@ TRACE_REQUEST_FUNC(ProcessSize) { os::jfr_report_process_size(); } -TRACE_REQUEST_FUNC(OpenFDs) { - os::jfr_report_openfds(); +TRACE_REQUEST_FUNC(LibcStatistics) { + os::jfr_report_libc_statistics(); } TRACE_REQUEST_FUNC(JVMInformation) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index d22d825074af9..dd1c74a8d28f0 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -850,7 +850,7 @@ class os: AllStatic { // Send JFR memory info event static void jfr_report_memory_info() NOT_JFR_RETURN(); static void jfr_report_process_size() NOT_JFR_RETURN(); - static void jfr_report_openfds() NOT_JFR_RETURN(); + static void jfr_report_libc_statistics() NOT_JFR_RETURN(); // Returns number of OS threads for the calling process; -1 if the information cannot be obtained. // Note: this includes, but is not limited to, the number of threads the JVM has created or that diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 2bff0bec00513..0c32979b72d25 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -965,12 +965,12 @@ forRemoval - + true - 5000 ms + 1000 ms - + true 1000 ms From dbefae0c8eb3a17a5af033d496ed2bcd617d3368 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Wed, 13 Aug 2025 16:10:06 +0200 Subject: [PATCH 06/21] wip --- src/hotspot/os/aix/os_aix.inline.hpp | 2 +- src/hotspot/os/bsd/os_bsd.inline.hpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 26 +++++++++----------- src/hotspot/os/linux/trimCHeapDCmd.cpp | 20 +++++++++------ src/hotspot/os/windows/os_windows.inline.hpp | 2 +- src/hotspot/share/jfr/metadata/metadata.xml | 9 +++++++ src/hotspot/share/runtime/os.hpp | 2 +- src/hotspot/share/runtime/trimNativeHeap.cpp | 25 +++++++++---------- src/jdk.jfr/share/conf/jfr/profile.jfc | 6 +++++ test/hotspot/gtest/runtime/test_os.cpp | 4 +-- 10 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.inline.hpp b/src/hotspot/os/aix/os_aix.inline.hpp index f7e7ee8abc65a..6989b9199a3ca 100644 --- a/src/hotspot/os/aix/os_aix.inline.hpp +++ b/src/hotspot/os/aix/os_aix.inline.hpp @@ -54,6 +54,6 @@ inline void os::map_stack_shadow_pages(address sp) { // Trim-native support, stubbed out for now, may be enabled later inline bool os::can_trim_native_heap() { return false; } -inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } +inline bool os::trim_native_heap(os::size_change_t& rss_change) { return false; } #endif // OS_AIX_OS_AIX_INLINE_HPP diff --git a/src/hotspot/os/bsd/os_bsd.inline.hpp b/src/hotspot/os/bsd/os_bsd.inline.hpp index 2049b337118a3..224b5b2dae2c1 100644 --- a/src/hotspot/os/bsd/os_bsd.inline.hpp +++ b/src/hotspot/os/bsd/os_bsd.inline.hpp @@ -57,6 +57,6 @@ inline void os::map_stack_shadow_pages(address sp) { // Trim-native support, stubbed out for now, may be enabled later inline bool os::can_trim_native_heap() { return false; } -inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } +inline bool os::trim_native_heap(os::size_change_t& rss_change) { return false; } #endif // OS_BSD_OS_BSD_INLINE_HPP diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 56807f98f71fa..98ed84eaa1e90 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -5404,27 +5404,23 @@ int os::Linux::malloc_info(FILE* stream) { } #endif // __GLIBC__ -bool os::trim_native_heap(os::size_change_t* rss_change) { +bool os::trim_native_heap(os::size_change_t& rss_change) { #ifdef __GLIBC__ os::Linux::process_info_t info1; os::Linux::process_info_t info2; - bool have_info1 = rss_change != nullptr && - os::Linux::query_process_info(&info1); + bool have_info1 = os::Linux::query_process_info(&info1); ::malloc_trim(0); - bool have_info2 = rss_change != nullptr && have_info1 && - os::Linux::query_process_info(&info2); + bool have_info2 = have_info1 && os::Linux::query_process_info(&info2); ssize_t delta = (ssize_t) -1; - if (rss_change != nullptr) { - if (have_info1 && have_info2 && - info1.vmrss != -1 && info2.vmrss != -1 && - info1.vmswap != -1 && info2.vmswap != -1) { - // Note: query_process_memory_info returns values in K - rss_change->before = (info1.vmrss + info1.vmswap) * K; - rss_change->after = (info2.vmrss + info2.vmswap) * K; - } else { - rss_change->after = rss_change->before = SIZE_MAX; - } + if (have_info1 && have_info2 && + info1.vmrss != -1 && info2.vmrss != -1 && + info1.vmswap != -1 && info2.vmswap != -1) { + // Note: query_process_memory_info returns values in K + rss_change.before = (info1.vmrss + info1.vmswap) * K; + rss_change.after = (info2.vmrss + info2.vmswap) * K; + } else { + rss_change.after = rss_change.before = SIZE_MAX; } g_num_trims ++; diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index 6b4cad03c1b55..21ef55d0db1d1 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -23,28 +23,34 @@ * */ +#include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "runtime/os.inline.hpp" #include "trimCHeapDCmd.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/ticks.hpp" #include void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { if (os::can_trim_native_heap()) { os::size_change_t sc; - if (os::trim_native_heap(&sc)) { + const Ticks ticks1 = Ticks::now(); + if (os::trim_native_heap(sc)) { + const Ticks ticks2 = Ticks::now(); + const double duration = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; _output->print("Trim native heap: "); if (sc.after != SIZE_MAX) { - const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before); - const char sign = sc.after < sc.before ? '-' : '+'; - _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", - PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); + const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); + _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%zd) (%.3fms)", + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), delta, duration); // Also log if native trim log is active - log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", - PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); + log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (%zd) (%.3fms)", + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), delta, duration); + JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, true, duration, sc.before, sc.after, delta);) } else { _output->print_cr("(no details available)."); } diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index 41471224b6c44..c424e9de57062 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -88,6 +88,6 @@ inline void PlatformMonitor::notify_all() { // Trim-native support, stubbed out for now, may be enabled later inline bool os::can_trim_native_heap() { return false; } -inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } +inline bool os::trim_native_heap(os::size_change_t& rss_change) { return false; } #endif // OS_WINDOWS_OS_WINDOWS_INLINE_HPP diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 47f6213e5c026..7983bc7204b66 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1340,6 +1340,15 @@ + + + + + + + + diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index dd1c74a8d28f0..83e134e1e241f 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -494,7 +494,7 @@ class os: AllStatic { // Note: If trimming succeeded but no size change information could be obtained, // rss_change.after will contain SIZE_MAX upon return. struct size_change_t { size_t before; size_t after; }; - static bool trim_native_heap(size_change_t* rss_change = nullptr); + static bool trim_native_heap(size_change_t& rss_change); // A diagnostic function to print memory mappings in the given range. static void print_memory_mappings(char* addr, size_t bytes, outputStream* st); diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp index 875bcb8e0c819..61255555da54e 100644 --- a/src/hotspot/share/runtime/trimNativeHeap.cpp +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -24,6 +24,7 @@ * */ +#include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" @@ -36,6 +37,7 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/ticks.hpp" #include "utilities/vmError.hpp" class NativeHeapTrimmerThread : public NamedThread { @@ -137,24 +139,21 @@ class NativeHeapTrimmerThread : public NamedThread { os::size_change_t sc = { 0, 0 }; LogTarget(Info, trimnative) lt; - const bool logging_enabled = lt.is_enabled(); - - // We only collect size change information if we are logging; save the access to procfs otherwise. - if (os::trim_native_heap(logging_enabled ? &sc : nullptr)) { + const Ticks ticks1 = Ticks::now(); + if (os::trim_native_heap(sc)) { + const Ticks ticks2 = Ticks::now(); + const double duration_millis = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; _num_trims_performed++; - if (logging_enabled) { - double t2 = now(); + if (lt.is_enabled()) { if (sc.after != SIZE_MAX) { - const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before); - const char sign = sc.after < sc.before ? '-' : '+'; - log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ") %.3fms", + const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); + log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (%zd) %.3fms", _num_trims_performed, - PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta), - to_ms(t2 - t1)); + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), delta, duration_millis); + JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, false, duration_millis, sc.before, sc.after, delta);) } else { log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): complete (no details) %.3fms", - _num_trims_performed, - to_ms(t2 - t1)); + _num_trims_performed, duration_millis); } } } diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 0c32979b72d25..597b143d33ae4 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -975,6 +975,12 @@ 1000 ms + + true + false + 0 ms + + diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index ce4050ab0f3cb..d07c76fafac69 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -1030,7 +1030,7 @@ TEST_VM(os, trim_native_heap) { EXPECT_TRUE(os::can_trim_native_heap()); os::size_change_t sc; sc.before = sc.after = (size_t)-1; - EXPECT_TRUE(os::trim_native_heap(&sc)); + EXPECT_TRUE(os::trim_native_heap(sc)); tty->print_cr("%zu->%zu", sc.before, sc.after); // Regardless of whether we freed memory, both before and after // should be somewhat believable numbers (RSS). @@ -1040,8 +1040,6 @@ TEST_VM(os, trim_native_heap) { ASSERT_GT(max, sc.before); ASSERT_LE(min, sc.after); ASSERT_GT(max, sc.after); - // Should also work - EXPECT_TRUE(os::trim_native_heap()); } #else TEST_VM(os, trim_native_heap) { From 9cfc6e867d25c35ac2f03957faf2c9e338554007 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Wed, 13 Aug 2025 16:21:00 +0200 Subject: [PATCH 07/21] wip --- src/hotspot/share/jfr/metadata/metadata.xml | 3 ++- src/jdk.jfr/share/conf/jfr/default.jfc | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 7983bc7204b66..f59732484408b 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1333,7 +1333,7 @@ - + @@ -1605,4 +1605,5 @@ + diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index eb3b8626722c0..619ef3ca7c2b2 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -965,6 +965,22 @@ forRemoval + + true + 5000 ms + + + + true + 5000 ms + + + + false + false + 0 ms + + From 8e61454abfab4767b66db0ae89250dd17fd6bb57 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Wed, 13 Aug 2025 18:43:06 +0200 Subject: [PATCH 08/21] test --- src/hotspot/share/nmt/mallocTracker.hpp | 31 ---- src/hotspot/share/nmt/nmtUsage.cpp | 3 +- src/hotspot/share/nmt/nmtUsage.hpp | 5 - .../event/runtime/TestProcessSizeEvent.java | 165 ++++++++++++++++++ test/lib/jdk/test/lib/jfr/EventNames.java | 3 + 5 files changed, 169 insertions(+), 38 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index 651ca170dbc38..e71c9374d4b58 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -168,11 +168,6 @@ class MallocMemorySnapshot { return _all_mallocs.count() * MallocHeader::malloc_overhead(); } - size_t malloc_size(MemTag mem_tag) const { - const MallocMemory* mm = by_tag(mem_tag); - return mm->malloc_size() + mm->arena_size(); - } - // Total malloc invocation count size_t total_count() const { return _all_mallocs.count(); @@ -263,18 +258,6 @@ class MallocMemorySummary : AllStatic { // either global or the category limit static inline bool check_exceeds_limit(size_t s, MemTag mem_tag); - // Total malloc'd memory amount - static size_t total() { - return as_snapshot()->total(); - } - - static size_t total_peak_malloc() { - return as_snapshot()->total_peak(); - } - - static size_t malloc_size(MemTag mem_tag) { - return as_snapshot()->malloc_size(mem_tag); - } }; // Main class called from MemTracker to track malloc activities @@ -336,20 +319,6 @@ class MallocTracker : AllStatic { assert(memblock != nullptr, "null pointer"); return (const MallocHeader*)memblock -1; } - - // Total malloc'd memory amount - static size_t total_malloc() { - return MallocMemorySummary::total(); - } - - // Total malloc'd memory amount - static size_t total_peak_malloc() { - return MallocMemorySummary::total_peak_malloc(); - } - - static size_t malloc_size(MemTag mem_tag) { - return MallocMemorySummary::malloc_size(mem_tag); - } }; #endif // SHARE_NMT_MALLOCTRACKER_HPP diff --git a/src/hotspot/share/nmt/nmtUsage.cpp b/src/hotspot/share/nmt/nmtUsage.cpp index e35b3dbadbde9..0d2aa40ea07e9 100644 --- a/src/hotspot/share/nmt/nmtUsage.cpp +++ b/src/hotspot/share/nmt/nmtUsage.cpp @@ -37,8 +37,7 @@ const NMTUsageOptions NMTUsage::OptionsNoTS = { false, true, true }; NMTUsage::NMTUsage(NMTUsageOptions options) : _malloc_by_type(), - _malloc_total(0), - _malloc_peak(0), + _malloc_total(), _vm_by_type(), _vm_total(), _usage_options(options) { } diff --git a/src/hotspot/share/nmt/nmtUsage.hpp b/src/hotspot/share/nmt/nmtUsage.hpp index 2e25ca9875e96..2011e7ed240f5 100644 --- a/src/hotspot/share/nmt/nmtUsage.hpp +++ b/src/hotspot/share/nmt/nmtUsage.hpp @@ -44,7 +44,6 @@ class NMTUsage : public CHeapObj { private: size_t _malloc_by_type[mt_number_of_tags]; size_t _malloc_total; - size_t _malloc_peak; NMTUsagePair _vm_by_type[mt_number_of_tags]; NMTUsagePair _vm_total; @@ -65,10 +64,6 @@ class NMTUsage : public CHeapObj { size_t total_committed() const; size_t reserved(MemTag mem_tag) const; size_t committed(MemTag mem_tag) const; - - size_t malloc_total() const { return _malloc_total; } - size_t malloc_peak() const { return _malloc_peak; } - size_t malloc_unsafe() const { return _malloc_by_type[(int)mtOther]; } }; #endif // SHARE_NMT_NMTUSAGE_HPP diff --git a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java new file mode 100644 index 0000000000000..ec4f33f25bb84 --- /dev/null +++ b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2022, 2025, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.runtime; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import static jdk.test.lib.Asserts.*; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires (os.family=="linux") & !vm.musl + * @library /test/lib + * @modules jdk.jfr + * jdk.management + * @run main/othervm -Xms16m -Xmx128m -Xlog:gc -Xlog:trimnative -XX:TrimNativeHeapInterval=500 jdk.jfr.event.runtime.TestProcessSizeEvent + */ +public class TestProcessSizeEvent { + private final static String ProcessSizeEventName = EventNames.ProcessSize; + private final static String LibcStatisticsEventName = EventNames.LibcStatistics; + + private final static long K = 1024; + private final static long M = K * K; + private final static long G = M * K; + private final static long toAllocate = M * 64; + private final static long sleepTime = 6000; + + private static ArrayList data = new ArrayList(); + + private static void doNoisyThings() throws InterruptedException { + // Allocate some memory in the C-Heap (using DBBs). + // Touch that memory to drive up RSS. + long bufferSize = M; + long numBuffers = toAllocate / bufferSize; + ByteBuffer[] list = new ByteBuffer[(int)numBuffers]; + for (int i = 0; i < list.length; i++) { + list[i] = ByteBuffer.allocateDirect((int)bufferSize); + } + for (ByteBuffer b : list) { + while (b.position() < b.capacity()) { + b.put((byte) 'A'); + if (b.position() < (b.capacity() - K)) { + b.position(b.position() + (int)K); + } + } + } + Thread.sleep(sleepTime); + } + + private static void generateEvents(Recording recording) throws Exception { + recording.enable(ProcessSizeEventName).with("period", "500ms"); + recording.enable(LibcStatisticsEventName).with("period", "500ms"); + + recording.start(); + + doNoisyThings(); + + recording.stop(); + } + + private static void verifyExpectedProcessSizeEvents(List events) throws Exception { + List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(ProcessSizeEventName)).toList(); + + assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + ProcessSizeEventName); + + for (RecordedEvent event : filteredEvents) { + System.out.println(event); + long vsize = event.getLong("vsize"); + long rss = event.getLong("rss"); + long rssPeak = event.getLong("rssPeak"); + long rssAnon = event.getLong("rssAnon"); + long rssFile = event.getLong("rssFile"); + long rssShmem = event.getLong("rssShmem"); + long swap = event.getLong("swap"); + long pagetable = event.getLong("pagetable"); + + long reasonableVsizeHigh = G * K; // vsize can get very large + long reasonableVsizeLow = 100 * M; + assertGreaterThan(vsize, reasonableVsizeLow, "Must be"); + assertLessThan(vsize, reasonableVsizeHigh, "Must be"); + + long reasonableRSSHigh = G; // probably a lot less + long reasonableRSSLow = 10 * M; // probably a lot less + assertGreaterThan(rss, reasonableRSSLow, "Must be"); + assertLessThan(rss, reasonableRSSHigh, "Must be"); + + assertGreaterThan(rssPeak, reasonableRSSLow, "Must be"); + assertLessThan(rssPeak, reasonableRSSHigh, "Must be"); + + assertGreaterThan(rssAnon, reasonableRSSLow / 2, "Must be"); + assertLessThanOrEqual(rssAnon, rss, "Must be"); + + assertGreaterThanOrEqual(rssFile, 0L, "Must be"); + assertLessThanOrEqual(rssFile, rss, "Must be"); + + assertGreaterThanOrEqual(rssShmem, 0L, "Must be"); + assertLessThanOrEqual(rssShmem, rss, "Must be"); + + assertGreaterThan(pagetable, 0L, "Must be"); + + assertGreaterThanOrEqual(swap, 0L, "Must be"); + } + } + + private static void verifyExpectedLibcStatisticsEvents(List events) throws Exception { + List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(LibcStatisticsEventName)).toList(); + + assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + LibcStatisticsEventName); + + for (RecordedEvent event : filteredEvents) { + System.out.println(event); + long mallocOutstanding = event.getLong("mallocOutstanding"); + long mallocRetained = event.getLong("mallocRetained"); + long trims = event.getLong("trims"); + + assertGreaterThan(mallocOutstanding, 0L, "Must be"); + long reasonableLimit = G; // vsize can get very large + assertLessThan(mallocOutstanding, reasonableLimit, "Must be"); + + assertGreaterThan(mallocRetained, 0L, "Must be"); + assertLessThan(mallocRetained, reasonableLimit, "Must be"); + + // we activated periodic trims and should see them + assertGreaterThan(trims, 0L, "Must be"); + } + } + + public static void main(String[] args) throws Exception { + try (Recording recording = new Recording()) { + generateEvents(recording); + var events = Events.fromRecording(recording); + verifyExpectedProcessSizeEvents(events); + verifyExpectedLibcStatisticsEvents(events); + } + } +} diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index a00898358a865..61c8265da99eb 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -195,6 +195,9 @@ public class EventNames { public static final String NetworkUtilization = PREFIX + "NetworkUtilization"; public static final String ProcessStart = PREFIX + "ProcessStart"; public static final String ResidentSetSize = PREFIX + "ResidentSetSize"; + public static final String ProcessSize = PREFIX + "ProcessSize"; + public static final String LibcStatistics = PREFIX + "LibcStatistics"; + public static final String LibcHeapTrim = PREFIX + "LibcHeapTrim"; // JDK public static final String FileForce = PREFIX + "FileForce"; From 68e854d11497dfe0d7501fcb1064144dc5d1c4cc Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 07:01:35 +0200 Subject: [PATCH 09/21] wip --- src/hotspot/os/linux/trimCHeapDCmd.cpp | 8 ++++---- src/hotspot/share/runtime/trimNativeHeap.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index 21ef55d0db1d1..8c9917a29819a 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -45,11 +45,11 @@ void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { _output->print("Trim native heap: "); if (sc.after != SIZE_MAX) { const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); - _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%zd) (%.3fms)", - PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), delta, duration); + _output->print_cr("RSS+Swap: %zuM->%zuM (%zdM) (%.3fms)", + sc.before / M, sc.after / M, delta / M, duration); // Also log if native trim log is active - log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (%zd) (%.3fms)", - PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), delta, duration); + log_info(trimnative)("Manual Trim: %zuM->%zuM (%zdM) (%.3fms)", + sc.before / M, sc.after / M, delta / M, duration); JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, true, duration, sc.before, sc.after, delta);) } else { _output->print_cr("(no details available)."); diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp index 61255555da54e..e42adee392562 100644 --- a/src/hotspot/share/runtime/trimNativeHeap.cpp +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -147,9 +147,9 @@ class NativeHeapTrimmerThread : public NamedThread { if (lt.is_enabled()) { if (sc.after != SIZE_MAX) { const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); - log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (%zd) %.3fms", + log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): %zuM->%zuM (%zsM) %.3fms", _num_trims_performed, - PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), delta, duration_millis); + sc.before / M, sc.after / M, delta / M, duration_millis); JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, false, duration_millis, sc.before, sc.after, delta);) } else { log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): complete (no details) %.3fms", From 39ff781ce11dab59093a1b367a0840604ec6784e Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 07:30:03 +0200 Subject: [PATCH 10/21] fix TrimCHeap test --- src/hotspot/os/linux/trimCHeapDCmd.cpp | 14 +++++++------- src/hotspot/share/runtime/trimNativeHeap.cpp | 11 ++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index 8c9917a29819a..a890939b66715 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -41,16 +41,16 @@ void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { const Ticks ticks1 = Ticks::now(); if (os::trim_native_heap(sc)) { const Ticks ticks2 = Ticks::now(); - const double duration = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; + const double duration = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; // millis _output->print("Trim native heap: "); if (sc.after != SIZE_MAX) { - const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); - _output->print_cr("RSS+Swap: %zuM->%zuM (%zdM) (%.3fms)", - sc.before / M, sc.after / M, delta / M, duration); + const size_t recovered = MIN((size_t)0, sc.after - sc.before); + _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); // Also log if native trim log is active - log_info(trimnative)("Manual Trim: %zuM->%zuM (%zdM) (%.3fms)", - sc.before / M, sc.after / M, delta / M, duration); - JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, true, duration, sc.before, sc.after, delta);) + log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); + JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, true, duration, sc.before, sc.after, -recovered);) } else { _output->print_cr("(no details available)."); } diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp index e42adee392562..bc8e7bd5cc8d7 100644 --- a/src/hotspot/share/runtime/trimNativeHeap.cpp +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -142,18 +142,19 @@ class NativeHeapTrimmerThread : public NamedThread { const Ticks ticks1 = Ticks::now(); if (os::trim_native_heap(sc)) { const Ticks ticks2 = Ticks::now(); - const double duration_millis = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; + const double duration = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; // millis _num_trims_performed++; if (lt.is_enabled()) { if (sc.after != SIZE_MAX) { + const size_t recovered = MIN((size_t)0, sc.after - sc.before); const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); - log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): %zuM->%zuM (%zsM) %.3fms", + log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", _num_trims_performed, - sc.before / M, sc.after / M, delta / M, duration_millis); - JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, false, duration_millis, sc.before, sc.after, delta);) + PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); + JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, false, duration, sc.before, sc.after, delta);) } else { log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): complete (no details) %.3fms", - _num_trims_performed, duration_millis); + _num_trims_performed, duration); } } } From 406b7eb141e793dbdc81258ed4d30e1d35a8431b Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 07:39:00 +0200 Subject: [PATCH 11/21] fix defaultconfig test --- src/jdk.jfr/share/conf/jfr/default.jfc | 1 - src/jdk.jfr/share/conf/jfr/profile.jfc | 1 - 2 files changed, 2 deletions(-) diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 619ef3ca7c2b2..50f10c4270645 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -977,7 +977,6 @@ false - false 0 ms diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 597b143d33ae4..738b790ba2511 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -977,7 +977,6 @@ true - false 0 ms From 844ef9a8cb1639756a3123a177ad05fd511dacc3 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 07:41:54 +0200 Subject: [PATCH 12/21] Add test to workflow --- test/jdk/TEST.groups | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 8bb270561dc53..345de73080c72 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -561,7 +561,8 @@ jdk_jfr_sanity = \ jdk/jfr/event/gc/configuration/TestGCConfigurationEvent.java \ jdk/jfr/event/metadata/TestDefaultConfigurations.java \ jdk/jfr/startupargs/TestDumpOnExit.java \ - jdk/jfr/api/consumer/recordingstream/TestBasics.java + jdk/jfr/api/consumer/recordingstream/TestBasics.java \ + jdk/jfr/event/runtime/TestProcessSizeEvent.java svc_tools_sanity = From 3290edd1f15e245a6a27c0b349fc6dd7c83af5cb Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 08:39:39 +0200 Subject: [PATCH 13/21] tests --- src/hotspot/os/linux/trimCHeapDCmd.cpp | 2 +- src/hotspot/share/jfr/metadata/metadata.xml | 6 +- src/hotspot/share/runtime/trimNativeHeap.cpp | 3 +- src/hotspot/share/utilities/vmError.cpp | 1 + test/jdk/TEST.groups | 4 +- .../event/runtime/TestLibcHeapTrimEvent.java | 99 ++++++++++++++ .../runtime/TestLibcStatisticsEvent.java | 128 ++++++++++++++++++ .../event/runtime/TestProcessSizeEvent.java | 67 +++------ 8 files changed, 256 insertions(+), 54 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java create mode 100644 test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index a890939b66715..f03d99b252b92 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -50,7 +50,7 @@ void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { // Also log if native trim log is active log_info(trimnative)("Manual Trim: " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); - JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, true, duration, sc.before, sc.after, -recovered);) + JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, true, duration, sc.before, sc.after, recovered);) } else { _output->print_cr("(no details available)."); } diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index f59732484408b..3bd50d0aa2ede 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1344,9 +1344,9 @@ description="A Libc Trim operation"> - - - + + + diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp index bc8e7bd5cc8d7..e997a08d54f02 100644 --- a/src/hotspot/share/runtime/trimNativeHeap.cpp +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -147,11 +147,10 @@ class NativeHeapTrimmerThread : public NamedThread { if (lt.is_enabled()) { if (sc.after != SIZE_MAX) { const size_t recovered = MIN((size_t)0, sc.after - sc.before); - const ssize_t delta = checked_cast(sc.after) - checked_cast(sc.before); log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", _num_trims_performed, PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); - JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, false, duration, sc.before, sc.after, delta);) + JFR_ONLY(EventLibcHeapTrim::commit(ticks1, ticks2, false, duration, sc.before, sc.after, recovered);) } else { log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): complete (no details) %.3fms", _num_trims_performed, duration); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index bd882a7ef3cbb..ea6fa42c38894 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1507,6 +1507,7 @@ void VMError::print_vm_info(outputStream* st) { // STEP("Compiler Memory Statistic") CompilationMemoryStatistic::print_final_report(st); + st->cr(); // STEP("printing periodic trim state") NativeHeapTrimmer::print_state(st); diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 345de73080c72..909d8ee286142 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -562,7 +562,9 @@ jdk_jfr_sanity = \ jdk/jfr/event/metadata/TestDefaultConfigurations.java \ jdk/jfr/startupargs/TestDumpOnExit.java \ jdk/jfr/api/consumer/recordingstream/TestBasics.java \ - jdk/jfr/event/runtime/TestProcessSizeEvent.java + jdk/jfr/event/runtime/TestProcessSizeEvent.java \ + jdk/jfr/event/runtime/TestLibcStatisticsEvent.java \ + jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java \ svc_tools_sanity = diff --git a/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java b/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java new file mode 100644 index 0000000000000..6ec4af07ecdd1 --- /dev/null +++ b/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.runtime; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static jdk.test.lib.Asserts.*; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires (os.family=="linux") & !vm.musl + * @library /test/lib + * @modules jdk.jfr + * jdk.management + * @run main/othervm -Xmx64m -Xlog:trimnative -XX:TrimNativeHeapInterval=200 jdk.jfr.event.runtime.TestLibcHeapTrimEvent + */ +public class TestLibcHeapTrimEvent { + private final static long K = 1024; + private final static long M = K * K; + private final static long G = M * K; + private final static long sleepTime = 5000; // Time enough for the trimmer thread to get started and engaged + + private static ArrayList data = new ArrayList(); + + private static void generateEvents(Recording recording) throws Exception { + recording.enable(EventNames.LibcHeapTrim); + + recording.start(); + + Thread.sleep(sleepTime); + + recording.stop(); + } + + private static void verifyExpectedEvents(List events) throws Exception { + List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(EventNames.LibcHeapTrim)).toList(); + +System.out.println("COUNT " + events.stream().count()); +System.out.println(events.stream().collect(Collectors.toList())); + + assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + EventNames.LibcHeapTrim); + + for (RecordedEvent event : filteredEvents) { + System.out.println(event); + double duration = event.getLong("duration"); + long rssPre = event.getLong("rssPre"); + long rssPost = event.getLong("rssPost"); + long rssRecovered = event.getLong("rssRecovered"); + + long reasonableHigh = G; + assertGreaterThan(rssPre, 0L, "Must be"); + assertLessThan(rssPre, reasonableHigh, "Must be"); + + assertGreaterThan(rssPost, 0L, "Must be"); + assertLessThan(rssPost, reasonableHigh, "Must be"); + + assertGreaterThanOrEqual(rssRecovered, 0L, "Must be"); + assertLessThan(rssRecovered, rssPre, "Must be"); + } + } + + public static void main(String[] args) throws Exception { + try (Recording recording = new Recording()) { + generateEvents(recording); + var events = Events.fromRecording(recording); + verifyExpectedEvents(events); + } + } +} diff --git a/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java new file mode 100644 index 0000000000000..99cb6d34fcb02 --- /dev/null +++ b/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2022, 2025, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.runtime; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import static jdk.test.lib.Asserts.*; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires (os.family=="linux") & !vm.musl + * @library /test/lib + * @modules jdk.jfr + * jdk.management + * @run main/othervm -Xmx64m -XX:TrimNativeHeapInterval=250 -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics jdk.jfr.event.runtime.TestLibcStatisticsEvent + */ +public class TestLibcStatisticsEvent { + private final static String LibcStatisticsEventName = EventNames.LibcStatistics; + + private final static long K = 1024; + private final static long M = K * K; + private final static long G = M * K; + private final static long toAllocate = M * 64; + private final static long sleepTime = 3000; + + private static ArrayList data = new ArrayList(); + + private static void doNoisyThings() throws InterruptedException { + // Allocate some memory in the C-Heap (using DBBs). + // Touch that memory to drive up RSS. + long bufferSize = M; + long numBuffers = toAllocate / bufferSize; + ByteBuffer[] list = new ByteBuffer[(int)numBuffers]; + for (int i = 0; i < list.length; i++) { + list[i] = ByteBuffer.allocateDirect((int)bufferSize); + } + for (ByteBuffer b : list) { + while (b.position() < b.capacity()) { + b.put((byte) 'A'); + if (b.position() < (b.capacity() - K)) { + b.position(b.position() + (int)K); + } + } + } + Thread.sleep(sleepTime); + } + + private static void generateEvents(Recording recording) throws Exception { + recording.enable(LibcStatisticsEventName).with("period", "250ms"); + + recording.start(); + + doNoisyThings(); + + recording.stop(); + } + + private static void verifyExpectedEvents(List events) throws Exception { + List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(LibcStatisticsEventName)).toList(); + + assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + LibcStatisticsEventName); + + long mallocOutstanding = 0, mallocRetained = 0; + long trims = 0; + + RecordedEvent last = null; + for (RecordedEvent event : filteredEvents) { + System.out.println(event); + mallocOutstanding = event.getLong("mallocOutstanding"); + mallocRetained = event.getLong("mallocRetained"); + trims = event.getLong("trims"); + + long reasonableLow = K; // probably a lot more, but the very first events may not show much yet + long reasonableLimit = G; // probably a lot less + assertGreaterThan(mallocOutstanding, reasonableLow); + assertLessThan(mallocOutstanding, reasonableLimit); + + assertGreaterThan(mallocRetained, 0L); + assertLessThan(mallocRetained, reasonableLimit); + + last = event; + } + + assertNotNull(last); + // we activated periodic trims and by the time the last event was taken we should see them + assertGreaterThan(trims, 0L, "Must be"); + // by this time we also should have allocated the majority of what we allocate + assertGreaterThan(mallocOutstanding, toAllocate / 2, "Must be"); + } + + public static void main(String[] args) throws Exception { + try (Recording recording = new Recording()) { + generateEvents(recording); + var events = Events.fromRecording(recording); + verifyExpectedEvents(events); + } + } +} diff --git a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java index ec4f33f25bb84..1b2294de0ddfc 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -42,7 +42,7 @@ * @library /test/lib * @modules jdk.jfr * jdk.management - * @run main/othervm -Xms16m -Xmx128m -Xlog:gc -Xlog:trimnative -XX:TrimNativeHeapInterval=500 jdk.jfr.event.runtime.TestProcessSizeEvent + * @run main/othervm -Xmx64m -XX:+UnlockDiagnosticVMOptions -XX:+PrintVMInfoAtExit jdk.jfr.event.runtime.TestProcessSizeEvent */ public class TestProcessSizeEvent { private final static String ProcessSizeEventName = EventNames.ProcessSize; @@ -52,7 +52,7 @@ public class TestProcessSizeEvent { private final static long M = K * K; private final static long G = M * K; private final static long toAllocate = M * 64; - private final static long sleepTime = 6000; + private final static long sleepTime = 3000; private static ArrayList data = new ArrayList(); @@ -77,8 +77,7 @@ private static void doNoisyThings() throws InterruptedException { } private static void generateEvents(Recording recording) throws Exception { - recording.enable(ProcessSizeEventName).with("period", "500ms"); - recording.enable(LibcStatisticsEventName).with("period", "500ms"); + recording.enable(ProcessSizeEventName).with("period", "250ms"); recording.start(); @@ -87,11 +86,9 @@ private static void generateEvents(Recording recording) throws Exception { recording.stop(); } - private static void verifyExpectedProcessSizeEvents(List events) throws Exception { + private static void verifyExpectedEvents(List events) throws Exception { List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(ProcessSizeEventName)).toList(); - assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + ProcessSizeEventName); - for (RecordedEvent event : filteredEvents) { System.out.println(event); long vsize = event.getLong("vsize"); @@ -105,52 +102,29 @@ private static void verifyExpectedProcessSizeEvents(List events) long reasonableVsizeHigh = G * K; // vsize can get very large long reasonableVsizeLow = 100 * M; - assertGreaterThan(vsize, reasonableVsizeLow, "Must be"); - assertLessThan(vsize, reasonableVsizeHigh, "Must be"); + assertGreaterThan(vsize, reasonableVsizeLow); + assertLessThan(vsize, reasonableVsizeHigh); long reasonableRSSHigh = G; // probably a lot less long reasonableRSSLow = 10 * M; // probably a lot less - assertGreaterThan(rss, reasonableRSSLow, "Must be"); - assertLessThan(rss, reasonableRSSHigh, "Must be"); - - assertGreaterThan(rssPeak, reasonableRSSLow, "Must be"); - assertLessThan(rssPeak, reasonableRSSHigh, "Must be"); - - assertGreaterThan(rssAnon, reasonableRSSLow / 2, "Must be"); - assertLessThanOrEqual(rssAnon, rss, "Must be"); - - assertGreaterThanOrEqual(rssFile, 0L, "Must be"); - assertLessThanOrEqual(rssFile, rss, "Must be"); - - assertGreaterThanOrEqual(rssShmem, 0L, "Must be"); - assertLessThanOrEqual(rssShmem, rss, "Must be"); + assertGreaterThan(rss, reasonableRSSLow); + assertLessThan(rss, reasonableRSSHigh); - assertGreaterThan(pagetable, 0L, "Must be"); + assertGreaterThan(rssPeak, reasonableRSSLow); + assertLessThan(rssPeak, reasonableRSSHigh); - assertGreaterThanOrEqual(swap, 0L, "Must be"); - } - } - - private static void verifyExpectedLibcStatisticsEvents(List events) throws Exception { - List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(LibcStatisticsEventName)).toList(); + assertGreaterThan(rssAnon, reasonableRSSLow / 2); + assertLessThanOrEqual(rssAnon, rss); - assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + LibcStatisticsEventName); - - for (RecordedEvent event : filteredEvents) { - System.out.println(event); - long mallocOutstanding = event.getLong("mallocOutstanding"); - long mallocRetained = event.getLong("mallocRetained"); - long trims = event.getLong("trims"); + assertGreaterThanOrEqual(rssFile, 0L); + assertLessThanOrEqual(rssFile, rss); - assertGreaterThan(mallocOutstanding, 0L, "Must be"); - long reasonableLimit = G; // vsize can get very large - assertLessThan(mallocOutstanding, reasonableLimit, "Must be"); + assertGreaterThanOrEqual(rssShmem, 0L); + assertLessThanOrEqual(rssShmem, rss); - assertGreaterThan(mallocRetained, 0L, "Must be"); - assertLessThan(mallocRetained, reasonableLimit, "Must be"); + assertGreaterThan(pagetable, 0L); - // we activated periodic trims and should see them - assertGreaterThan(trims, 0L, "Must be"); + assertGreaterThanOrEqual(swap, 0L); } } @@ -158,8 +132,7 @@ public static void main(String[] args) throws Exception { try (Recording recording = new Recording()) { generateEvents(recording); var events = Events.fromRecording(recording); - verifyExpectedProcessSizeEvents(events); - verifyExpectedLibcStatisticsEvents(events); + verifyExpectedEvents(events); } } } From 9e118927a57df565a09855269c7b74af1f591658 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 09:12:42 +0200 Subject: [PATCH 14/21] Add nonjava thread count; add test for thread statistics --- src/hotspot/share/jfr/metadata/metadata.xml | 3 ++- src/hotspot/share/jfr/periodic/jfrPeriodic.cpp | 4 +++- src/hotspot/share/runtime/nonJavaThread.cpp | 8 ++++++++ src/hotspot/share/runtime/nonJavaThread.hpp | 1 + .../jfr/event/runtime/TestJavaThreadStatisticsEvent.java | 3 +++ 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 3bd50d0aa2ede..f6bc568306daf 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -884,11 +884,12 @@ - + + diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index ce3c5656f18be..bd6302ba3443e 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -57,6 +57,7 @@ #include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/interfaceSupport.inline.hpp" +#include "runtime/nonJavaThread.hpp" #include "runtime/os.hpp" #include "runtime/os_perf.hpp" #include "runtime/thread.inline.hpp" @@ -552,11 +553,12 @@ TRACE_REQUEST_FUNC(SwapSpace) { TRACE_REQUEST_FUNC(JavaThreadStatistics) { EventJavaThreadStatistics event; - event.set_osThreadCount(os::num_process_threads()); event.set_activeCount(ThreadService::get_live_thread_count()); event.set_daemonCount(ThreadService::get_daemon_thread_count()); event.set_accumulatedCount(ThreadService::get_total_thread_count()); event.set_peakCount(ThreadService::get_peak_thread_count()); + event.set_osThreadCount(os::num_process_threads()); + event.set_nonJavaThreadCount(NonJavaThread::count()); event.commit(); } diff --git a/src/hotspot/share/runtime/nonJavaThread.cpp b/src/hotspot/share/runtime/nonJavaThread.cpp index 71c44d2a83b2f..dde1ef8e41e16 100644 --- a/src/hotspot/share/runtime/nonJavaThread.cpp +++ b/src/hotspot/share/runtime/nonJavaThread.cpp @@ -46,11 +46,13 @@ class NonJavaThread::List { public: NonJavaThread* volatile _head; SingleWriterSynchronizer _protect; + static volatile int _count; List() : _head(nullptr), _protect() {} }; NonJavaThread::List NonJavaThread::_the_list; +volatile int NonJavaThread::List::_count = 0; NonJavaThread::Iterator::Iterator() : _protect_enter(_the_list._protect.enter()), @@ -78,6 +80,7 @@ void NonJavaThread::add_to_the_list() { BarrierSet::barrier_set()->on_thread_attach(this); Atomic::release_store(&_next, _the_list._head); Atomic::release_store(&_the_list._head, this); + Atomic::inc(&_the_list._count); } void NonJavaThread::remove_from_the_list() { @@ -92,6 +95,7 @@ void NonJavaThread::remove_from_the_list() { break; } } + Atomic::dec(&_the_list._count); } // Wait for any in-progress iterators. Concurrent synchronize is not // allowed, so do it while holding a dedicated lock. Outside and distinct @@ -101,6 +105,10 @@ void NonJavaThread::remove_from_the_list() { _next = nullptr; // Safe to drop the link now. } +int NonJavaThread::count() { + return Atomic::load(&_the_list._count); +} + void NonJavaThread::pre_run() { add_to_the_list(); diff --git a/src/hotspot/share/runtime/nonJavaThread.hpp b/src/hotspot/share/runtime/nonJavaThread.hpp index 6d9095924d98e..fdfec90799b83 100644 --- a/src/hotspot/share/runtime/nonJavaThread.hpp +++ b/src/hotspot/share/runtime/nonJavaThread.hpp @@ -45,6 +45,7 @@ class NonJavaThread: public Thread { public: NonJavaThread(); ~NonJavaThread(); + static int count(); class Iterator; }; diff --git a/test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEvent.java index 92d86b1163cd1..aa4cb17eac3fd 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestJavaThreadStatisticsEvent.java @@ -74,6 +74,9 @@ public static void main(String[] args) throws Throwable { long daemonCount = Events.assertField(event, "daemonCount").atLeast(0L).getValue(); long activeCount = Events.assertField(event, "activeCount").atLeast(daemonCount).getValue(); long peakCount = Events.assertField(event, "peakCount").atLeast(activeCount).atLeast(1L).getValue(); + Events.assertField(event, "nonJavaThreadCount").atLeast(1L).getValue(); + Events.assertField(event, "osThreadCount").atLeast(activeCount).atLeast(1L).atMost(200L).getValue(); + Events.assertField(event, "accumulatedCount").atLeast(peakCount).getValue(); } assertTrue(isAnyFound, "Correct event not found"); From dfc18090b0c7dd0003c78bc22082dbdb2e9d5fec Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 09:13:05 +0200 Subject: [PATCH 15/21] typo --- src/hotspot/share/jfr/metadata/metadata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index f6bc568306daf..586d87dc4103e 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -888,7 +888,7 @@ - + From 84552d93079fff96a257b4c9ae6f52b096c94a1a Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 13:41:16 +0200 Subject: [PATCH 16/21] mac implementation --- src/hotspot/os/bsd/os_bsd.cpp | 79 ++++++++++++------- src/hotspot/os/bsd/os_bsd.hpp | 11 +++ src/hotspot/os/linux/trimCHeapDCmd.cpp | 2 +- .../share/jfr/periodic/jfrPeriodic.cpp | 3 +- src/hotspot/share/runtime/trimNativeHeap.cpp | 2 +- 5 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 35c4c9ba73b3b..0a9f35b2acc2e 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -207,20 +207,30 @@ julong os::physical_memory() { return Bsd::physical_memory(); } -size_t os::rss() { - size_t rss = 0; #ifdef __APPLE__ +bool os::Bsd::query_process_memory_info(os::Bsd::process_info_t* info) { mach_task_basic_info info; mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; - kern_return_t ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count); if (ret == KERN_SUCCESS) { - rss = info.resident_size; + info->vsize = info.virtual_size; + info->rss = info.resident_size; + // We've seen that resident_size_max sometimes trails resident_size with one page. + // Make sure we always report size <= peak + info->rssmax = MAX2(info.resident_size_max, info.resident_size); } -#endif // __APPLE__ +} +#endif - return rss; +size_t os::rss() { +#ifdef __APPLE__ + os::Bsd::process_info_t info; + if (os::Bsd::query_process_memory_info(&info)) { + return info.rss; + } +#endif // __APPLE__ + return 0; } // Cpu architecture string @@ -2447,36 +2457,51 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} #if INCLUDE_JFR -void os::jfr_report_memory_info() { -#ifdef __APPLE__ - mach_task_basic_info info; - mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; +#define JFR_WARN_ONCE(text) { \ + static bool first_warning = true; \ + if (first_warning) { \ + log_warning(jfr)(text); \ + first_warning = false; \ + } \ +} - kern_return_t ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count); - if (ret == KERN_SUCCESS) { - // Send the RSS JFR event +#ifdef __APPLE__ +void os::jfr_report_memory_info() { + os::Bsd::process_info_t info; + if (os::Bsd::query_process_memory_info(&info)) { EventResidentSetSize event; - event.set_size(info.resident_size); - // We've seen that resident_size_max sometimes trails resident_size with one page. - // Make sure we always report size <= peak - event.set_peak(MAX2(info.resident_size_max, info.resident_size)); + event.set_size(info.rss); + event.set_peak(info.rssmax); event.commit(); } else { - // Log a warning - static bool first_warning = true; - if (first_warning) { - log_warning(jfr)("Error fetching RSS values: task_info failed"); - first_warning = false; - } + JFR_WARN_ONCE("Error fetching RSS values: task_info failed"); + } +} + +void os::jfr_report_process_size() { + os::Bsd::process_info_t info; + if (os::Bsd::query_process_memory_info(&info)) { + EventProcessSize e; + e.set_vsize(info.vsize); + e.set_rss(info.rss); + e.set_rssPeak(info.rssmax); + e.set_rssAnon(0); + e.set_rssFile(0); + e.set_rssShmem(0); + e.set_pagetable(0); + e.set_swap(0); + e.commit(); + } else { + JFR_WARN_ONCE("Error fetching RSS values: task_info failed"); } - -#endif // __APPLE__ } - +#else +void os::jfr_report_memory_info() {} void os::jfr_report_process_size() {} +#endif // __APPLE__ + void os::jfr_report_libc_statistics() {} int os::num_process_threads() { return -1; } - #endif // INCLUDE_JFR bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 72de9ca597195..f4aa9aeb26aac 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -36,6 +36,17 @@ class os::Bsd { // mach_absolute_time static mach_timebase_info_data_t _timebase_info; static volatile uint64_t _max_abstime; + + // Output structure for query_process_memory_info() + struct process_info_t { + // see mach_task_basic_info_data_t + size_t vsize; // current virtual size + size_t rss; // current resident set size + size_t rssmax; // max resident set size + }; + + // Attempts to query memory information about the current process and return it in the output structure. + static bool query_process_memory_info(process_info_t* info); #endif static GrowableArray* _cpu_to_node; diff --git a/src/hotspot/os/linux/trimCHeapDCmd.cpp b/src/hotspot/os/linux/trimCHeapDCmd.cpp index f03d99b252b92..7b894e754bf39 100644 --- a/src/hotspot/os/linux/trimCHeapDCmd.cpp +++ b/src/hotspot/os/linux/trimCHeapDCmd.cpp @@ -44,7 +44,7 @@ void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { const double duration = (ticks2.microseconds() - ticks1.microseconds()) / 1000.0; // millis _output->print("Trim native heap: "); if (sc.after != SIZE_MAX) { - const size_t recovered = MIN((size_t)0, sc.after - sc.before); + const size_t recovered = MIN2((size_t)0, sc.after - sc.before); _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); // Also log if native trim log is active diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index bd6302ba3443e..3f615890467ea 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -557,7 +557,8 @@ TRACE_REQUEST_FUNC(JavaThreadStatistics) { event.set_daemonCount(ThreadService::get_daemon_thread_count()); event.set_accumulatedCount(ThreadService::get_total_thread_count()); event.set_peakCount(ThreadService::get_peak_thread_count()); - event.set_osThreadCount(os::num_process_threads()); + const int os_threads = os::num_process_threads(); + event.set_osThreadCount(os_threads == -1 ? 0 : os_threads); event.set_nonJavaThreadCount(NonJavaThread::count()); event.commit(); } diff --git a/src/hotspot/share/runtime/trimNativeHeap.cpp b/src/hotspot/share/runtime/trimNativeHeap.cpp index e997a08d54f02..665768e023ae0 100644 --- a/src/hotspot/share/runtime/trimNativeHeap.cpp +++ b/src/hotspot/share/runtime/trimNativeHeap.cpp @@ -146,7 +146,7 @@ class NativeHeapTrimmerThread : public NamedThread { _num_trims_performed++; if (lt.is_enabled()) { if (sc.after != SIZE_MAX) { - const size_t recovered = MIN((size_t)0, sc.after - sc.before); + const size_t recovered = MIN2((size_t)0, sc.after - sc.before); log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (-" PROPERFMT ") (%.3fms)", _num_trims_performed, PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), PROPERFMTARGS(recovered), duration); From 9195bfd912ccd34a643799848c360af9f1b859af Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 15:32:25 +0200 Subject: [PATCH 17/21] wip --- src/hotspot/os/bsd/os_bsd.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 0a9f35b2acc2e..1286cf84b86e0 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -208,17 +208,17 @@ julong os::physical_memory() { } #ifdef __APPLE__ -bool os::Bsd::query_process_memory_info(os::Bsd::process_info_t* info) { +bool os::Bsd::query_process_memory_info(os::Bsd::process_info_t* pi) { mach_task_basic_info info; mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; kern_return_t ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count); if (ret == KERN_SUCCESS) { - info->vsize = info.virtual_size; - info->rss = info.resident_size; + pi->vsize = info.virtual_size; + pi->rss = info.resident_size; // We've seen that resident_size_max sometimes trails resident_size with one page. // Make sure we always report size <= peak - info->rssmax = MAX2(info.resident_size_max, info.resident_size); + pi->rssmax = MAX2(info.resident_size_max, info.resident_size); } } #endif From f12bb7efab303947b4d640594a6f4648b1622ec5 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Thu, 14 Aug 2025 16:12:19 +0200 Subject: [PATCH 18/21] fix mac --- src/hotspot/os/bsd/os_bsd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 1286cf84b86e0..68eb80bb8627e 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -219,7 +219,9 @@ bool os::Bsd::query_process_memory_info(os::Bsd::process_info_t* pi) { // We've seen that resident_size_max sometimes trails resident_size with one page. // Make sure we always report size <= peak pi->rssmax = MAX2(info.resident_size_max, info.resident_size); + return true; } + return false; } #endif From bd70381934564f51778b759262a9cd44844a9a90 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Fri, 15 Aug 2025 09:13:44 +0200 Subject: [PATCH 19/21] MacOS tests --- .../event/runtime/TestProcessSizeEvent.java | 85 +++++++++++-------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java index 1b2294de0ddfc..4bf04acdf562c 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java @@ -25,6 +25,7 @@ import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Platform; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; @@ -38,7 +39,7 @@ * @test * @requires vm.flagless * @requires vm.hasJFR - * @requires (os.family=="linux") & !vm.musl + * @requires (os.family=="linux") | (os.family=="mac") * @library /test/lib * @modules jdk.jfr * jdk.management @@ -51,7 +52,7 @@ public class TestProcessSizeEvent { private final static long K = 1024; private final static long M = K * K; private final static long G = M * K; - private final static long toAllocate = M * 64; + private final static long toAllocate = M * 16; private final static long sleepTime = 3000; private static ArrayList data = new ArrayList(); @@ -86,45 +87,57 @@ private static void generateEvents(Recording recording) throws Exception { recording.stop(); } + final static long reasonableVsizeHigh = G * 10000; + final static long reasonableVsizeLow = 100 * M; + final static long reasonableRSSHigh = G; + // We may run on undersized test machines, in which case the test may be heavily swapping. This in turn + // can falsify the reported RSS (which is why we report Swap as a metric, too). + // To avoid false positives, RSS low is chosen to be a very defensive low number. + final static long reasonableRSSLow = 5 * M; + + private static void verifyExpectedEventCommon(RecordedEvent event) throws Exception { + long vsize = Events.assertField(event, "vsize"). + atLeast(reasonableVsizeLow).atMost(reasonableVsizeHigh).getValue(); + long rss = Events.assertField(event, "rss"). + atLeast(reasonableRSSLow).atMost(reasonableRSSHigh).atMost(vsize).getValue(); + Events.assertField(event, "rssPeak"). + atLeast(rss).atMost(reasonableRSSHigh); + } + + private static void verifyExpectedEventLinux(RecordedEvent event) throws Exception { + verifyExpectedEventCommon(event); + long vsize = event.getValue("vsize"); + long rss = event.getValue("rss"); + Events.assertField(event, "rssPeak"). + atLeast(rss).atMost(reasonableRSSHigh); + Events.assertField(event, "rssAnon"). + atLeast(reasonableRSSLow / 8).atMost(reasonableRSSHigh).atMost(rss); + Events.assertField(event, "rssFile"). + atLeast(0L).atMost(reasonableRSSHigh).atMost(rss); + Events.assertField(event, "rssShm"). + atLeast(0L).atMost(reasonableRSSHigh).atMost(rss); + Events.assertField(event, "swap"). + atLeast(0L).atMost(vsize); + Events.assertField(event, "pagetable"). + atLeast(0L).atMost(vsize / 8); + } + + private static void verifyExpectedEventMacOS(RecordedEvent event) throws Exception { + verifyExpectedEventCommon(event); + } + private static void verifyExpectedEvents(List events) throws Exception { List filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(ProcessSizeEventName)).toList(); assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + ProcessSizeEventName); for (RecordedEvent event : filteredEvents) { System.out.println(event); - long vsize = event.getLong("vsize"); - long rss = event.getLong("rss"); - long rssPeak = event.getLong("rssPeak"); - long rssAnon = event.getLong("rssAnon"); - long rssFile = event.getLong("rssFile"); - long rssShmem = event.getLong("rssShmem"); - long swap = event.getLong("swap"); - long pagetable = event.getLong("pagetable"); - - long reasonableVsizeHigh = G * K; // vsize can get very large - long reasonableVsizeLow = 100 * M; - assertGreaterThan(vsize, reasonableVsizeLow); - assertLessThan(vsize, reasonableVsizeHigh); - - long reasonableRSSHigh = G; // probably a lot less - long reasonableRSSLow = 10 * M; // probably a lot less - assertGreaterThan(rss, reasonableRSSLow); - assertLessThan(rss, reasonableRSSHigh); - - assertGreaterThan(rssPeak, reasonableRSSLow); - assertLessThan(rssPeak, reasonableRSSHigh); - - assertGreaterThan(rssAnon, reasonableRSSLow / 2); - assertLessThanOrEqual(rssAnon, rss); - - assertGreaterThanOrEqual(rssFile, 0L); - assertLessThanOrEqual(rssFile, rss); - - assertGreaterThanOrEqual(rssShmem, 0L); - assertLessThanOrEqual(rssShmem, rss); - - assertGreaterThan(pagetable, 0L); - - assertGreaterThanOrEqual(swap, 0L); + if (Platform.isLinux()) { + verifyExpectedEventLinux(event); + } else if (Platform.isOSX()) { + verifyExpectedEventMacOS(event); + } else { + throw new RuntimeException("Unsupported"); + } } } From d2dd455ab0e0921df70b7b05ceee452414490530 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Fri, 15 Aug 2025 10:48:33 +0200 Subject: [PATCH 20/21] Windows --- src/hotspot/os/bsd/os_bsd.cpp | 1 + src/hotspot/os/linux/os_linux.cpp | 1 + src/hotspot/os/windows/os_windows.cpp | 90 +++++++++++-------- src/hotspot/os/windows/os_windows.hpp | 12 +++ src/hotspot/share/jfr/metadata/metadata.xml | 1 + .../event/runtime/TestProcessSizeEvent.java | 51 +++++------ 6 files changed, 93 insertions(+), 63 deletions(-) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 68eb80bb8627e..3be40dfbb0f84 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2490,6 +2490,7 @@ void os::jfr_report_process_size() { e.set_rssAnon(0); e.set_rssFile(0); e.set_rssShmem(0); + e.set_committed(0); e.set_pagetable(0); e.set_swap(0); e.commit(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 98ed84eaa1e90..448710d1431fc 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2695,6 +2695,7 @@ void os::jfr_report_process_size() { e.set_rssAnon(info.rssanon * K); e.set_rssFile(info.rssfile * K); e.set_rssShmem(info.rssshmem * K); + e.set_committed(0); e.set_pagetable(info.vmpte * K); e.set_swap(info.vmswap * K); e.commit(); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 96db1340f79eb..09a50100bab7b 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -884,19 +884,29 @@ julong os::physical_memory() { return win32::physical_memory(); } -size_t os::rss() { - size_t rss = 0; +bool os::win32::query_process_memory_info(os::win32::process_info_t* info) { PROCESS_MEMORY_COUNTERS_EX pmex; - ZeroMemory(&pmex, sizeof(PROCESS_MEMORY_COUNTERS_EX)); + ZeroMemory(&pmex, sizeof(pmex)); pmex.cb = sizeof(pmex); - BOOL ret = GetProcessMemoryInfo( - GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmex, sizeof(pmex)); + const BOOL ret = GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmex, sizeof(pmex)); if (ret) { - rss = pmex.WorkingSetSize; + info->working_set_size = pmex.WorkingSetSize; + info->working_set_size_peak = pmex.PeakWorkingSetSize; + info->commit_charge = pmex.PagefileUsage; + info->commit_charge_peak = pmex.PeakPagefileUsage; + info->pagefaults = pmex.PageFaultCount; + return true; } - return rss; + return false; } +size_t os::rss() { + os::win32::process_info_t pi; + if (os::win32::query_process_memory_info(&pi)) { + return pi.working_set_size; + } + return 0; +} int os::active_processor_count() { // User has overridden the number of active processors @@ -2141,19 +2151,13 @@ void os::print_memory_info(outputStream* st) { } // extended memory statistics for a process - PROCESS_MEMORY_COUNTERS_EX pmex; - ZeroMemory(&pmex, sizeof(PROCESS_MEMORY_COUNTERS_EX)); - pmex.cb = sizeof(pmex); - int r2 = GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmex, sizeof(pmex)); + os::win32::process_info_t pi; + if (os::win32::query_process_memory_info(&pi)) { + st->print("\ncurrent process WorkingSet (physical memory assigned to process): %zuM, peak: %zuM", + pi.working_set_size / M, pi.working_set_size_peak / M); - if (r2 != 0) { - st->print("\ncurrent process WorkingSet (physical memory assigned to process): " INT64_FORMAT "M, ", - (int64_t) pmex.WorkingSetSize >> 20); - st->print("peak: " INT64_FORMAT "M\n", (int64_t) pmex.PeakWorkingSetSize >> 20); - - st->print("current process commit charge (\"private bytes\"): " INT64_FORMAT "M, ", - (int64_t) pmex.PrivateUsage >> 20); - st->print("peak: " INT64_FORMAT "M", (int64_t) pmex.PeakPagefileUsage >> 20); + st->print("current process commit charge (\"private bytes\"): %zuM, peak: %zuM", + pi.commit_charge / M, pi.commit_charge_peak / M); } else { st->print("\nGetProcessMemoryInfo did not succeed so we miss some memory values."); } @@ -6215,29 +6219,45 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) { #if INCLUDE_JFR -void os::jfr_report_memory_info() { - PROCESS_MEMORY_COUNTERS_EX pmex; - ZeroMemory(&pmex, sizeof(PROCESS_MEMORY_COUNTERS_EX)); - pmex.cb = sizeof(pmex); +#define JFR_WARN_ONCE(text) { \ + static bool first_warning = true; \ + if (first_warning) { \ + log_warning(jfr)(text); \ + first_warning = false; \ + } \ +} - BOOL ret = GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmex, sizeof(pmex)); - if (ret != 0) { - // Send the RSS JFR event +void os::jfr_report_memory_info() { + os::win32::process_info_t pi; + if (os::win32::query_process_memory_info(&pi)) { EventResidentSetSize event; - event.set_size(pmex.WorkingSetSize); - event.set_peak(pmex.PeakWorkingSetSize); + event.set_size(pi.working_set_size); + event.set_peak(pi.working_set_size_peak); event.commit(); } else { - // Log a warning - static bool first_warning = true; - if (first_warning) { - log_warning(jfr)("Error fetching RSS values: GetProcessMemoryInfo failed"); - first_warning = false; - } + JFR_WARN_ONCE("Error fetching RSS values: GetProcessMemoryInfo failed"); + } +} + +void os::jfr_report_process_size() { + os::win32::process_info_t pi; + if (os::win32::query_process_memory_info(&pi)) { + EventProcessSize e; + e.set_vsize(0); + e.set_rss(pi.working_set_size); + e.set_rssPeak(pi.working_set_size_peak); + e.set_rssAnon(0); + e.set_rssFile(0); + e.set_rssShmem(0); + e.set_committed(pi.commit_charge); + e.set_pagetable(0); + e.set_swap(0); + e.commit(); + } else { + JFR_WARN_ONCE("Error fetching RSS values: GetProcessMemoryInfo failed"); } } -void os::jfr_report_process_size() {} void os::jfr_report_libc_statistics() {} int os::num_process_threads() { return -1; } diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 1aba43fb3d255..760bb8fd81034 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -150,6 +150,18 @@ class os::win32 { // signal support static void* install_signal_handler(int sig, signal_handler_t handler); static void* user_handler(); + + // Output structure for query_process_memory_info(); see GetProcessMemoryInfo + struct process_info_t { + size_t working_set_size; + size_t working_set_size_peak; + size_t commit_charge; + size_t commit_charge_peak; + unsigned pagefaults; + }; + + // Attempts to query memory information about the current process and return it in the output structure. + static bool query_process_memory_info(process_info_t* info); }; #endif // OS_WINDOWS_OS_WINDOWS_HPP diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 586d87dc4103e..5f0231a6965b0 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1331,6 +1331,7 @@ + diff --git a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java index 4bf04acdf562c..226ae4d8e6490 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java @@ -39,7 +39,7 @@ * @test * @requires vm.flagless * @requires vm.hasJFR - * @requires (os.family=="linux") | (os.family=="mac") + * @requires (os.family != "aix") * @library /test/lib * @modules jdk.jfr * jdk.management @@ -95,35 +95,33 @@ private static void generateEvents(Recording recording) throws Exception { // To avoid false positives, RSS low is chosen to be a very defensive low number. final static long reasonableRSSLow = 5 * M; - private static void verifyExpectedEventCommon(RecordedEvent event) throws Exception { + private static void verifyExpectedEventLinux(RecordedEvent event) throws Exception { long vsize = Events.assertField(event, "vsize"). atLeast(reasonableVsizeLow).atMost(reasonableVsizeHigh).getValue(); long rss = Events.assertField(event, "rss"). atLeast(reasonableRSSLow).atMost(reasonableRSSHigh).atMost(vsize).getValue(); - Events.assertField(event, "rssPeak"). - atLeast(rss).atMost(reasonableRSSHigh); + Events.assertField(event, "rssPeak").atLeast(rss).atMost(reasonableRSSHigh); + Events.assertField(event, "rssPeak").atLeast(rss).atMost(reasonableRSSHigh); + Events.assertField(event, "rssAnon").atLeast(reasonableRSSLow / 8).atMost(reasonableRSSHigh).atMost(rss); + Events.assertField(event, "rssFile").atLeast(0L).atMost(reasonableRSSHigh).atMost(rss); + Events.assertField(event, "rssShmem").atLeast(0L).atMost(reasonableRSSHigh).atMost(rss); + Events.assertField(event, "swap").atLeast(0L).atMost(vsize); + Events.assertField(event, "pagetable").atLeast(0L).atMost(vsize / 8); } - private static void verifyExpectedEventLinux(RecordedEvent event) throws Exception { - verifyExpectedEventCommon(event); - long vsize = event.getValue("vsize"); - long rss = event.getValue("rss"); - Events.assertField(event, "rssPeak"). - atLeast(rss).atMost(reasonableRSSHigh); - Events.assertField(event, "rssAnon"). - atLeast(reasonableRSSLow / 8).atMost(reasonableRSSHigh).atMost(rss); - Events.assertField(event, "rssFile"). - atLeast(0L).atMost(reasonableRSSHigh).atMost(rss); - Events.assertField(event, "rssShm"). - atLeast(0L).atMost(reasonableRSSHigh).atMost(rss); - Events.assertField(event, "swap"). - atLeast(0L).atMost(vsize); - Events.assertField(event, "pagetable"). - atLeast(0L).atMost(vsize / 8); + private static void verifyExpectedEventWindows(RecordedEvent event) throws Exception { + long rss = Events.assertField(event, "rss"). + atLeast(reasonableRSSLow).atMost(reasonableRSSHigh).getValue(); + Events.assertField(event, "rssPeak").atLeast(rss).atMost(reasonableRSSHigh); + Events.assertField(event, "committed").atLeast(4 * K).atMost(reasonableVsizeHigh); } private static void verifyExpectedEventMacOS(RecordedEvent event) throws Exception { - verifyExpectedEventCommon(event); + long vsize = Events.assertField(event, "vsize"). + atLeast(reasonableVsizeLow).atMost(reasonableVsizeHigh).getValue(); + long rss = Events.assertField(event, "rss"). + atLeast(reasonableRSSLow).atMost(reasonableRSSHigh).atMost(vsize).getValue(); + Events.assertField(event, "rssPeak").atLeast(rss).atMost(reasonableRSSHigh); } private static void verifyExpectedEvents(List events) throws Exception { @@ -131,13 +129,10 @@ private static void verifyExpectedEvents(List events) throws Exce assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + ProcessSizeEventName); for (RecordedEvent event : filteredEvents) { System.out.println(event); - if (Platform.isLinux()) { - verifyExpectedEventLinux(event); - } else if (Platform.isOSX()) { - verifyExpectedEventMacOS(event); - } else { - throw new RuntimeException("Unsupported"); - } + if (Platform.isLinux()) verifyExpectedEventLinux(event); + else if (Platform.isWindows()) verifyExpectedEventWindows(event); + else if (Platform.isOSX()) verifyExpectedEventMacOS(event); + else throw new RuntimeException("Unsupported OS"); } } From 39e282ae9941505ddfd98e6bef9102610ebe4364 Mon Sep 17 00:00:00 2001 From: tstuefe Date: Fri, 15 Aug 2025 17:05:52 +0200 Subject: [PATCH 21/21] copyrights --- src/hotspot/os/aix/os_aix.inline.hpp | 2 +- src/hotspot/os/bsd/os_bsd.hpp | 2 +- src/hotspot/os/bsd/os_bsd.inline.hpp | 2 +- src/hotspot/os/linux/os_linux.hpp | 2 +- src/hotspot/os/windows/os_windows.hpp | 2 +- src/hotspot/os/windows/os_windows.inline.hpp | 2 +- src/hotspot/share/nmt/nmtUsage.hpp | 2 +- src/hotspot/share/runtime/nonJavaThread.hpp | 2 +- test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java | 1 + test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java | 3 ++- test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java | 1 + 11 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.inline.hpp b/src/hotspot/os/aix/os_aix.inline.hpp index 6989b9199a3ca..8fa6ae6293d61 100644 --- a/src/hotspot/os/aix/os_aix.inline.hpp +++ b/src/hotspot/os/aix/os_aix.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index f4aa9aeb26aac..7d3f7162eb6a8 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 diff --git a/src/hotspot/os/bsd/os_bsd.inline.hpp b/src/hotspot/os/bsd/os_bsd.inline.hpp index 224b5b2dae2c1..54ef02d74c749 100644 --- a/src/hotspot/os/bsd/os_bsd.inline.hpp +++ b/src/hotspot/os/bsd/os_bsd.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index b652dda548692..fe75b65cff9a7 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 760bb8fd81034..a6551a30519e6 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index c424e9de57062..752194d162ae6 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 diff --git a/src/hotspot/share/nmt/nmtUsage.hpp b/src/hotspot/share/nmt/nmtUsage.hpp index 2011e7ed240f5..a180522a812a1 100644 --- a/src/hotspot/share/nmt/nmtUsage.hpp +++ b/src/hotspot/share/nmt/nmtUsage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 diff --git a/src/hotspot/share/runtime/nonJavaThread.hpp b/src/hotspot/share/runtime/nonJavaThread.hpp index fdfec90799b83..d84a24b3f70b7 100644 --- a/src/hotspot/share/runtime/nonJavaThread.hpp +++ b/src/hotspot/share/runtime/nonJavaThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 diff --git a/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java b/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java index 6ec4af07ecdd1..843982c3c1323 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestLibcHeapTrimEvent.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, IBM Corporation. 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 diff --git a/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java index 99cb6d34fcb02..158700b62f161 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestLibcStatisticsEvent.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, IBM Corporation. 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 diff --git a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java index 226ae4d8e6490..b3551bc66c19b 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestProcessSizeEvent.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, IBM Corporation. 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