mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-13 17:33:10 +00:00
8368527: JMX: Add an MXBeans method to query GC CPU time
Reviewed-by: phh, kevinw
This commit is contained in:
parent
09b25cd0a2
commit
812add27ab
@ -53,7 +53,8 @@ enum {
|
||||
JMM_VERSION_2 = 0x20020000, // JDK 10
|
||||
JMM_VERSION_3 = 0x20030000, // JDK 14
|
||||
JMM_VERSION_4 = 0x20040000, // JDK 21
|
||||
JMM_VERSION = JMM_VERSION_4
|
||||
JMM_VERSION_5 = 0x20050000, // JDK 26
|
||||
JMM_VERSION = JMM_VERSION_5
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -81,6 +82,7 @@ typedef enum {
|
||||
JMM_GC_TIME_MS = 9, /* Total accumulated time spent in collection */
|
||||
JMM_GC_COUNT = 10, /* Total number of collections */
|
||||
JMM_JVM_UPTIME_MS = 11, /* The JVM uptime in milliseconds */
|
||||
JMM_TOTAL_GC_CPU_TIME = 12, /* Total accumulated GC CPU time */
|
||||
|
||||
JMM_INTERNAL_ATTRIBUTE_INDEX = 100,
|
||||
JMM_CLASS_LOADED_BYTES = 101, /* Number of bytes loaded instance classes */
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
volatile bool CPUTimeUsage::Error::_has_error = false;
|
||||
|
||||
static inline jlong thread_cpu_time_or_zero(Thread* thread) {
|
||||
assert(!Universe::is_shutting_down(), "Should not query during shutdown");
|
||||
jlong cpu_time = os::thread_cpu_time(thread);
|
||||
if (cpu_time == -1) {
|
||||
CPUTimeUsage::Error::mark_error();
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "runtime/vmOperations.hpp"
|
||||
#include "services/classLoadingService.hpp"
|
||||
#include "services/cpuTimeUsage.hpp"
|
||||
#include "services/diagnosticCommand.hpp"
|
||||
#include "services/diagnosticFramework.hpp"
|
||||
#include "services/finalizerService.hpp"
|
||||
@ -889,6 +890,21 @@ static jint get_num_flags() {
|
||||
return count;
|
||||
}
|
||||
|
||||
static jlong get_gc_cpu_time() {
|
||||
if (!os::is_thread_cpu_time_supported()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
MutexLocker hl(Heap_lock);
|
||||
if (Universe::heap()->is_shutting_down()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return CPUTimeUsage::GC::total();
|
||||
}
|
||||
}
|
||||
|
||||
static jlong get_long_attribute(jmmLongAttribute att) {
|
||||
switch (att) {
|
||||
case JMM_CLASS_LOADED_COUNT:
|
||||
@ -915,6 +931,9 @@ static jlong get_long_attribute(jmmLongAttribute att) {
|
||||
case JMM_JVM_UPTIME_MS:
|
||||
return Management::ticks_to_ms(os::elapsed_counter());
|
||||
|
||||
case JMM_TOTAL_GC_CPU_TIME:
|
||||
return get_gc_cpu_time();
|
||||
|
||||
case JMM_COMPILE_TOTAL_TIME_MS:
|
||||
return Management::ticks_to_ms(CompileBroker::total_compilation_ticks());
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -267,6 +267,43 @@ public interface MemoryMXBean extends PlatformManagedObject {
|
||||
*/
|
||||
public MemoryUsage getNonHeapMemoryUsage();
|
||||
|
||||
/**
|
||||
* Returns the approximate accumulated time, in nanoseconds,
|
||||
* spent in garbage collection (GC).
|
||||
*
|
||||
* <p> The time spent in spent in GC is the CPU time used by
|
||||
* all GC activity, including any overhead, which means the
|
||||
* result may be non-zero even if no GC has occurred.
|
||||
*
|
||||
* This method returns {@code -1} if the platform does
|
||||
* not support this operation or the information is not
|
||||
* available.
|
||||
*
|
||||
* @apiNote
|
||||
* May be used in conjunction with {@link jdk.management/com.sun.management.OperatingSystemMXBean#getProcessCpuTime()}
|
||||
* for calculating the GC's usage of CPU time as a whole.
|
||||
*
|
||||
* @implNote The specifics on what constitutes the time spent
|
||||
* in GC are highly implementation dependent. In the HotSpot
|
||||
* Virtual Machine, this time includes relevant
|
||||
* implementation-specific details such as driver threads,
|
||||
* workers, VM Operations and string deduplication (if
|
||||
* enabled). Driver threads may be created by a GC to
|
||||
* orchestrate its work. The return value can be -1 if called
|
||||
* when measurement is not possible, such as during shutdown.
|
||||
*
|
||||
* @implSpec The default implementation returns {@code -1}.
|
||||
*
|
||||
* @return the total accumulated CPU time for GC in
|
||||
* nanoseconds, or {@code -1}.
|
||||
*
|
||||
* @since 26
|
||||
*/
|
||||
@SuppressWarnings("doclint:reference")
|
||||
default public long getTotalGcCpuTime() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if verbose output for the memory system is enabled.
|
||||
*
|
||||
@ -302,5 +339,4 @@ public interface MemoryMXBean extends PlatformManagedObject {
|
||||
* @see java.lang.System#gc()
|
||||
*/
|
||||
public void gc();
|
||||
|
||||
}
|
||||
|
||||
@ -67,6 +67,10 @@ class MemoryImpl extends NotificationEmitterSupport
|
||||
Runtime.getRuntime().gc();
|
||||
}
|
||||
|
||||
public long getTotalGcCpuTime() {
|
||||
return jvm.getTotalGcCpuTime();
|
||||
}
|
||||
|
||||
// Need to make a VM call to get coherent value
|
||||
public MemoryUsage getHeapMemoryUsage() {
|
||||
return getMemoryUsage0(true);
|
||||
|
||||
@ -55,6 +55,7 @@ public interface VMManagement {
|
||||
public boolean getVerboseClass();
|
||||
|
||||
// Memory Subsystem
|
||||
public long getTotalGcCpuTime();
|
||||
public boolean getVerboseGC();
|
||||
|
||||
// Runtime Subsystem
|
||||
|
||||
@ -128,6 +128,7 @@ class VMManagementImpl implements VMManagement {
|
||||
public native boolean getVerboseClass();
|
||||
|
||||
// Memory Subsystem
|
||||
public native long getTotalGcCpuTime();
|
||||
public native boolean getVerboseGC();
|
||||
|
||||
// Runtime Subsystem
|
||||
|
||||
@ -121,6 +121,13 @@ Java_sun_management_VMManagementImpl_getUnloadedClassCount
|
||||
return count;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_management_VMManagementImpl_getTotalGcCpuTime
|
||||
(JNIEnv *env, jobject dummy)
|
||||
{
|
||||
return jmm_interface->GetLongAttribute(env, NULL, JMM_TOTAL_GC_CPU_TIME);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_management_VMManagementImpl_getVerboseGC
|
||||
(JNIEnv *env, jobject dummy)
|
||||
|
||||
@ -58,6 +58,10 @@ public class ServerMemoryMXBean extends ServerMXBean implements MemoryMXBean {
|
||||
return getIntAttribute(OBJECT_PENDING_FINALIZATION_COUNT);
|
||||
}
|
||||
|
||||
public long getTotalGcCpuTime() {
|
||||
throw new UnsupportedOperationException("This method is not supported");
|
||||
}
|
||||
|
||||
public boolean isVerbose() {
|
||||
return getBooleanAttribute(VERBOSE);
|
||||
}
|
||||
|
||||
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Epsilon
|
||||
* @requires vm.gc.Epsilon
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC StressGetTotalGcCpuTimeDuringShutdown
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Serial
|
||||
* @requires vm.gc.Serial
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseSerialGC StressGetTotalGcCpuTimeDuringShutdown
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Parallel
|
||||
* @requires vm.gc.Parallel
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseParallelGC StressGetTotalGcCpuTimeDuringShutdown
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=G1
|
||||
* @requires vm.gc.G1
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseG1GC StressGetTotalGcCpuTimeDuringShutdown
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=ZGC
|
||||
* @requires vm.gc.Z
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseZGC StressGetTotalGcCpuTimeDuringShutdown
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Shenandoah
|
||||
* @requires vm.gc.Shenandoah
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseShenandoahGC StressGetTotalGcCpuTimeDuringShutdown
|
||||
*/
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
|
||||
public class StressGetTotalGcCpuTimeDuringShutdown {
|
||||
static final ThreadMXBean mxThreadBean = ManagementFactory.getThreadMXBean();
|
||||
static final MemoryMXBean mxMemoryBean = ManagementFactory.getMemoryMXBean();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
if (!mxThreadBean.isThreadCpuTimeEnabled()) {
|
||||
return;
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (mxMemoryBean.getTotalGcCpuTime() != -1) {
|
||||
throw new RuntimeException("GC CPU time should be -1");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final int numberOfThreads = Runtime.getRuntime().availableProcessors() * 8;
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
Thread t = new Thread(() -> {
|
||||
while (true) {
|
||||
long gcCpuTimeFromThread = mxMemoryBean.getTotalGcCpuTime();
|
||||
if (gcCpuTimeFromThread < -1) {
|
||||
throw new RuntimeException("GC CPU time should never be less than -1 but was " + gcCpuTimeFromThread);
|
||||
}
|
||||
}
|
||||
});
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Epsilon
|
||||
* @requires vm.gc.Epsilon
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestGetTotalGcCpuTime
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Serial
|
||||
* @requires vm.gc.Serial
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseSerialGC TestGetTotalGcCpuTime
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Parallel
|
||||
* @requires vm.gc.Parallel
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseParallelGC TestGetTotalGcCpuTime
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=G1
|
||||
* @requires vm.gc.G1
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseG1GC TestGetTotalGcCpuTime
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=ZGC
|
||||
* @requires vm.gc.Z
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseZGC TestGetTotalGcCpuTime
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=Shenandoah
|
||||
* @requires vm.gc.Shenandoah
|
||||
* @bug 8368527
|
||||
* @summary Stress MemoryMXBean.getTotalGcCpuTime during shutdown
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UseShenandoahGC TestGetTotalGcCpuTime
|
||||
*/
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
|
||||
public class TestGetTotalGcCpuTime {
|
||||
static final ThreadMXBean mxThreadBean = ManagementFactory.getThreadMXBean();
|
||||
static final MemoryMXBean mxMemoryBean = ManagementFactory.getMemoryMXBean();
|
||||
static final boolean usingEpsilonGC = ManagementFactory.getRuntimeMXBean().getInputArguments().stream().anyMatch(p -> p.contains("-XX:+UseEpsilonGC"));
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
if (!mxThreadBean.isThreadCpuTimeEnabled()) {
|
||||
return;
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (mxMemoryBean.getTotalGcCpuTime() != -1) {
|
||||
throw new RuntimeException("GC CPU time should be -1");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
System.gc();
|
||||
long gcCpuTimeFromThread = mxMemoryBean.getTotalGcCpuTime();
|
||||
|
||||
if (usingEpsilonGC) {
|
||||
if (gcCpuTimeFromThread != 0) {
|
||||
throw new RuntimeException("Epsilon GC can't have any GC CPU time by definition");
|
||||
}
|
||||
} else {
|
||||
if (gcCpuTimeFromThread <= 0) {
|
||||
throw new RuntimeException("Some GC CPU time must have been reported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,6 +222,8 @@ public class MXBeanInteropTest1 {
|
||||
+ memory.getNonHeapMemoryUsage());
|
||||
System.out.println("getObjectPendingFinalizationCount\t\t"
|
||||
+ memory.getObjectPendingFinalizationCount());
|
||||
System.out.println("getTotalGcCpuTime\t\t"
|
||||
+ memory.getTotalGcCpuTime());
|
||||
System.out.println("isVerbose\t\t"
|
||||
+ memory.isVerbose());
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user