6523160: RuntimeMXBean.getUptime() returns negative values
Summary: RuntimeMXBean.getUptime() should be based on HR timers rather than on the OS time
Reviewed-by: dholmes, sla
--- a/jdk/make/java/management/mapfile-vers Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/make/java/management/mapfile-vers Sun Nov 10 20:05:03 2013 +0100
@@ -103,6 +103,7 @@
Java_sun_management_VMManagementImpl_getSafepointCount;
Java_sun_management_VMManagementImpl_getSafepointSyncTime;
Java_sun_management_VMManagementImpl_getStartupTime;
+ Java_sun_management_VMManagementImpl_getUptime0;
Java_sun_management_VMManagementImpl_getTotalApplicationNonStoppedTime;
Java_sun_management_VMManagementImpl_getTotalClassCount;
Java_sun_management_VMManagementImpl_getTotalCompileTime;
--- a/jdk/makefiles/mapfiles/libmanagement/mapfile-vers Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/makefiles/mapfiles/libmanagement/mapfile-vers Sun Nov 10 20:05:03 2013 +0100
@@ -103,6 +103,7 @@
Java_sun_management_VMManagementImpl_getSafepointCount;
Java_sun_management_VMManagementImpl_getSafepointSyncTime;
Java_sun_management_VMManagementImpl_getStartupTime;
+ Java_sun_management_VMManagementImpl_getUptime0;
Java_sun_management_VMManagementImpl_getTotalApplicationNonStoppedTime;
Java_sun_management_VMManagementImpl_getTotalClassCount;
Java_sun_management_VMManagementImpl_getTotalCompileTime;
--- a/jdk/src/share/classes/sun/management/RuntimeImpl.java Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/src/share/classes/sun/management/RuntimeImpl.java Sun Nov 10 20:05:03 2013 +0100
@@ -110,12 +110,7 @@
}
public long getUptime() {
- long current = System.currentTimeMillis();
-
- // TODO: If called from client side when we support
- // MBean proxy to read performance counters from shared memory,
- // need to check if the monitored VM exitd.
- return (current - vmStartupTime);
+ return jvm.getUptime();
}
public long getStartTime() {
--- a/jdk/src/share/classes/sun/management/VMManagement.java Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/src/share/classes/sun/management/VMManagement.java Sun Nov 10 20:05:03 2013 +0100
@@ -71,6 +71,7 @@
public String getBootClassPath();
public List<String> getVmArguments();
public long getStartupTime();
+ public long getUptime();
public int getAvailableProcessors();
// Compilation Subsystem
--- a/jdk/src/share/classes/sun/management/VMManagementImpl.java Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/src/share/classes/sun/management/VMManagementImpl.java Sun Nov 10 20:05:03 2013 +0100
@@ -179,6 +179,10 @@
return result;
}
+ public long getUptime() {
+ return getUptime0();
+ }
+
private List<String> vmArgs = null;
public synchronized List<String> getVmArguments() {
if (vmArgs == null) {
@@ -192,6 +196,7 @@
public native String[] getVmArguments0();
public native long getStartupTime();
+ private native long getUptime0();
public native int getAvailableProcessors();
// Compilation Subsystem
--- a/jdk/src/share/javavm/export/jmm.h Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/src/share/javavm/export/jmm.h Sun Nov 10 20:05:03 2013 +0100
@@ -78,6 +78,7 @@
JMM_COMPILE_TOTAL_TIME_MS = 8, /* Total accumulated time spent in compilation */
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_INTERNAL_ATTRIBUTE_INDEX = 100,
JMM_CLASS_LOADED_BYTES = 101, /* Number of bytes loaded instance classes */
--- a/jdk/src/share/native/sun/management/VMManagementImpl.c Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/src/share/native/sun/management/VMManagementImpl.c Sun Nov 10 20:05:03 2013 +0100
@@ -200,6 +200,13 @@
JMM_JVM_INIT_DONE_TIME_MS);
}
+JNIEXPORT jlong JNICALL
+Java_sun_management_VMManagementImpl_getUptime0
+ (JNIEnv *env, jobject dummy)
+{
+ return jmm_interface->GetLongAttribute(env, NULL, JMM_JVM_UPTIME_MS);
+}
+
JNIEXPORT jboolean JNICALL
Java_sun_management_VMManagementImpl_isThreadContentionMonitoringEnabled
(JNIEnv *env, jobject dummy)
--- a/jdk/test/java/lang/management/RuntimeMXBean/UpTime.java Sat Nov 09 14:30:03 2013 -0500
+++ b/jdk/test/java/lang/management/RuntimeMXBean/UpTime.java Sun Nov 10 20:05:03 2013 +0100
@@ -33,30 +33,34 @@
public class UpTime {
final static long DELAY = 5; // Seconds
final static long TIMEOUT = 30; // Minutes
- private static RuntimeMXBean metrics
+ final static long MULTIPLIER = 1000; // millisecond ticks
+
+ private static final RuntimeMXBean metrics
= ManagementFactory.getRuntimeMXBean();
public static void main(String argv[]) throws Exception {
long jvmStartTime = metrics.getStartTime();
- long systemStartOuter = System.currentTimeMillis();
+ // this will get an aproximate JVM uptime before starting this test
+ long jvmUptime = System.currentTimeMillis() - jvmStartTime;
+ long systemStartOuter = System_milliTime();
long metricsStart = metrics.getUptime();
- long systemStartInner = System.currentTimeMillis();
+ long systemStartInner = System_milliTime();
// This JVM might have been running for some time if this test runs
// in samevm mode. The sanity check should apply to the test uptime.
- long testUptime = metricsStart - (systemStartOuter - jvmStartTime);
+ long testUptime = metricsStart - jvmUptime;
// If uptime is more than 30 minutes then it looks like a bug in
// the method
- if (testUptime > TIMEOUT * 60 * 1000)
+ if (testUptime > TIMEOUT * 60 * MULTIPLIER)
throw new RuntimeException("Uptime of the JVM is more than 30 "
+ "minutes ("
- + (metricsStart / 60 / 1000)
+ + (metricsStart / 60 / MULTIPLIER)
+ " minutes).");
// Wait for DELAY seconds
Object o = new Object();
- while (System.currentTimeMillis() < systemStartInner + DELAY * 1000) {
+ while (System_milliTime() < systemStartInner + DELAY * MULTIPLIER) {
synchronized (o) {
try {
o.wait(DELAY * 1000);
@@ -67,23 +71,27 @@
}
}
- long systemEndInner = System.currentTimeMillis();
+ long systemEndInner = System_milliTime();
long metricsEnd = metrics.getUptime();
- long systemEndOuter = System.currentTimeMillis();
+ long systemEndOuter = System_milliTime();
long systemDifferenceInner = systemEndInner - systemStartInner;
long systemDifferenceOuter = systemEndOuter - systemStartOuter;
long metricsDifference = metricsEnd - metricsStart;
// Check the flow of time in RuntimeMXBean.getUptime(). See the
- // picture below
- if (metricsDifference < systemDifferenceInner)
+ // picture below.
+ // The measured times can be off by 1 due to conversions from
+ // nanoseconds to milliseconds, using different channels to read the
+ // HR timer and rounding error. Bigger difference will make the test
+ // fail.
+ if (metricsDifference - systemDifferenceInner < -1)
throw new RuntimeException("Flow of the time in "
+ "RuntimeMXBean.getUptime() ("
+ metricsDifference + ") is slower than "
+ " in system (" + systemDifferenceInner
+ ")");
- if (metricsDifference > systemDifferenceOuter)
+ if (metricsDifference - systemDifferenceOuter > 1)
throw new RuntimeException("Flow of the time in "
+ "RuntimeMXBean.getUptime() ("
+ metricsDifference + ") is faster than "
@@ -92,6 +100,10 @@
System.out.println("Test passed.");
}
+
+ private static long System_milliTime() {
+ return System.nanoTime() / 1000000; // nanoseconds / milliseconds;
+ }
}
/*