8307374: Add a JFR event for tracking RSS

Reviewed-by: stuefe, rcastanedalo
This commit is contained in:
Stefan Karlsson 2023-06-07 11:41:20 +00:00
parent 1de40f360f
commit 5722903d53
11 changed files with 211 additions and 0 deletions

View File

@ -3002,3 +3002,9 @@ bool os::supports_map_sync() {
} }
void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
#if INCLUDE_JFR
void os::jfr_report_memory_info() {}
#endif // INCLUDE_JFR

View File

@ -69,6 +69,9 @@
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#endif
// put OS-includes here // put OS-includes here
# include <dlfcn.h> # include <dlfcn.h>
@ -101,6 +104,7 @@
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#include <mach/task_info.h>
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#endif #endif
@ -2453,3 +2457,31 @@ bool os::start_debugging(char *buf, int buflen) {
} }
void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} 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;
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
EventResidentSetSize event;
event.set_size(info.resident_size);
event.set_peak(info.resident_size_max);
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;
}
}
#endif // __APPLE__
}
#endif // INCLUDE_JFR

View File

@ -77,6 +77,9 @@
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/powerOfTwo.hpp" #include "utilities/powerOfTwo.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#endif
// put OS-includes here // put OS-includes here
# include <sys/types.h> # include <sys/types.h>
@ -2470,6 +2473,28 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
print_sys_devices_cpu_info(st); print_sys_devices_cpu_info(st);
} }
#if INCLUDE_JFR
void os::jfr_report_memory_info() {
os::Linux::meminfo_t info;
if (os::Linux::query_process_memory_info(&info)) {
// Send the RSS JFR event
EventResidentSetSize event;
event.set_size(info.vmrss * K);
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;
}
}
}
#endif // INCLUDE_JFR
#if defined(AMD64) || defined(IA32) || defined(X32) #if defined(AMD64) || defined(IA32) || defined(X32)
const char* search_string = "model name"; const char* search_string = "model name";
#elif defined(M68K) #elif defined(M68K)

View File

@ -78,6 +78,9 @@
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
#include "windbghelp.hpp" #include "windbghelp.hpp"
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#endif
#ifdef _DEBUG #ifdef _DEBUG
#include <crtdbg.h> #include <crtdbg.h>
@ -6022,6 +6025,33 @@ 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);
BOOL ret = GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmex, sizeof(pmex));
if (ret != 0) {
// Send the RSS JFR event
EventResidentSetSize event;
event.set_size(pmex.WorkingSetSize);
event.set_peak(pmex.PeakWorkingSetSize);
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;
}
}
}
#endif // INCLUDE_JFR
// File conventions // File conventions
const char* os::file_separator() { return "\\"; } const char* os::file_separator() { return "\\"; }
const char* os::line_separator() { return "\r\n"; } const char* os::line_separator() { return "\r\n"; }

View File

@ -73,6 +73,11 @@
<Field type="string" name="name" label="Name" /> <Field type="string" name="name" label="Name" />
</Event> </Event>
<Event name="ResidentSetSize" category="Java Virtual Machine, Memory" label="Resident Set Size" description="Resident set size of the process" thread="false" period="everyChunk">
<Field type="ulong" contentType="bytes" name="size" label="Resident Set Size" description="Resident set size of the process" />
<Field type="ulong" contentType="bytes" name="peak" label="Resident Set Size Peak Value" description="Resident set size peak value of the process" />
</Event>
<!-- Ordinary and experimental events !--> <!-- Ordinary and experimental events !-->
<Event name="ThreadStart" category="Java Application" label="Java Thread Start" thread="true" startTime="false" stackTrace="true"> <Event name="ThreadStart" category="Java Application" label="Java Thread Start" thread="true" startTime="false" stackTrace="true">

View File

@ -95,6 +95,10 @@ PeriodicType JfrPeriodicEventSet::type(void) {
return _type; return _type;
} }
TRACE_REQUEST_FUNC(ResidentSetSize) {
os::jfr_report_memory_info();
}
TRACE_REQUEST_FUNC(JVMInformation) { TRACE_REQUEST_FUNC(JVMInformation) {
ResourceMark rm; ResourceMark rm;
EventJVMInformation event; EventJVMInformation event;

View File

@ -791,6 +791,9 @@ class os: AllStatic {
static size_t lasterror(char *buf, size_t len); static size_t lasterror(char *buf, size_t len);
static int get_last_error(); static int get_last_error();
// Send JFR memory info event
static void jfr_report_memory_info() NOT_JFR_RETURN();
// Replacement for strerror(). // Replacement for strerror().
// Will return the english description of the error (e.g. "File not found", as // Will return the english description of the error (e.g. "File not found", as
// suggested in the POSIX standard. // suggested in the POSIX standard.

View File

@ -7,6 +7,11 @@
<configuration version="2.0" label="Continuous" description="Low overhead configuration safe for continuous use in production environments, typically less than 1 % overhead." provider="Oracle"> <configuration version="2.0" label="Continuous" description="Low overhead configuration safe for continuous use in production environments, typically less than 1 % overhead." provider="Oracle">
<event name="jdk.ResidentSetSize">
<setting name="enabled">true</setting>
<setting name="period">1000 ms</setting>
</event>
<event name="jdk.ThreadAllocationStatistics"> <event name="jdk.ThreadAllocationStatistics">
<setting name="enabled">true</setting> <setting name="enabled">true</setting>
<setting name="period">everyChunk</setting> <setting name="period">everyChunk</setting>

View File

@ -7,6 +7,11 @@
<configuration version="2.0" label="Profiling" description="Low overhead configuration for profiling, typically around 2 % overhead." provider="Oracle"> <configuration version="2.0" label="Profiling" description="Low overhead configuration for profiling, typically around 2 % overhead." provider="Oracle">
<event name="jdk.ResidentSetSize">
<setting name="enabled">true</setting>
<setting name="period">1000 ms</setting>
</event>
<event name="jdk.ThreadAllocationStatistics"> <event name="jdk.ThreadAllocationStatistics">
<setting name="enabled">true</setting> <setting name="enabled">true</setting>
<setting name="period">everyChunk</setting> <setting name="period">everyChunk</setting>

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2022, 2023, 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 static jdk.test.lib.Asserts.assertGreaterThan;
import static jdk.test.lib.Asserts.assertLessThanOrEqual;
import java.util.ArrayList;
import java.util.List;
import jdk.jfr.Recording;
import jdk.jfr.consumer.RecordedEvent;
import jdk.test.lib.jfr.EventNames;
import jdk.test.lib.jfr.Events;
/**
* @test
* @key jfr
* @requires vm.hasJFR
* @library /test/lib
* @modules jdk.jfr
* jdk.management
* @run main/othervm -Xms16m -Xmx128m -Xlog:gc jdk.jfr.event.runtime.TestResidentSetSizeEvent true
*/
public class TestResidentSetSizeEvent {
private final static String ResidentSetSizeEvent = EventNames.ResidentSetSize;
private final static int Period = 1000;
private final static int K = 1024;
private static ArrayList<byte[]> data = new ArrayList<byte[]>();
private static void generateHeapContents() {
for (int i = 0 ; i < 64; i++) {
for (int j = 0; j < K; j++) {
data.add(new byte[K]);
}
}
}
private static void generateEvents(Recording recording) throws Exception {
recording.enable(ResidentSetSizeEvent).with("period", "everyChunk");
recording.start();
// Generate data to force heap to grow.
generateHeapContents();
recording.stop();
}
private static void verifyExpectedEventTypes(List<RecordedEvent> events) throws Exception {
List<RecordedEvent> filteredEvents = events.stream().filter(e -> e.getEventType().getName().equals(ResidentSetSizeEvent)).toList();
assertGreaterThan(filteredEvents.size(), 0, "Should exist events of type: " + ResidentSetSizeEvent);
for (RecordedEvent event : filteredEvents) {
long size = event.getLong("size");
long peak = event.getLong("peak");
assertGreaterThan(size, 0L, "Should be non-zero");
assertGreaterThan(peak, 0L, "Should be non-zero");
assertLessThanOrEqual(size, peak, "The size should be less than or equal to peak");
}
}
public static void main(String[] args) throws Exception {
try (Recording recording = new Recording()) {
generateEvents(recording);
var events = Events.fromRecording(recording);
verifyExpectedEventTypes(events);
}
}
}

View File

@ -186,6 +186,7 @@ public class EventNames {
public static final String PhysicalMemory = PREFIX + "PhysicalMemory"; public static final String PhysicalMemory = PREFIX + "PhysicalMemory";
public static final String NetworkUtilization = PREFIX + "NetworkUtilization"; public static final String NetworkUtilization = PREFIX + "NetworkUtilization";
public static final String ProcessStart = PREFIX + "ProcessStart"; public static final String ProcessStart = PREFIX + "ProcessStart";
public static final String ResidentSetSize = PREFIX + "ResidentSetSize";
// JDK // JDK
public static final String FileForce = PREFIX + "FileForce"; public static final String FileForce = PREFIX + "FileForce";