6523160: RuntimeMXBean.getUptime() returns negative values

RuntimeMXBean.getUptime() should be based on HR timers rather than on the OS time

Reviewed-by: dholmes, sla
This commit is contained in:
Jaroslav Bachorik 2013-11-10 20:05:03 +01:00
parent 3bffac4b48
commit db68e03030
8 changed files with 41 additions and 18 deletions

View File

@ -103,6 +103,7 @@ SUNWprivate_1.1 {
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;

View File

@ -103,6 +103,7 @@ SUNWprivate_1.1 {
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;

View File

@ -110,12 +110,7 @@ class RuntimeImpl implements RuntimeMXBean {
}
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() {

View File

@ -71,6 +71,7 @@ public interface VMManagement {
public String getBootClassPath();
public List<String> getVmArguments();
public long getStartupTime();
public long getUptime();
public int getAvailableProcessors();
// Compilation Subsystem

View File

@ -179,6 +179,10 @@ class VMManagementImpl implements VMManagement {
return result;
}
public long getUptime() {
return getUptime0();
}
private List<String> vmArgs = null;
public synchronized List<String> getVmArguments() {
if (vmArgs == null) {
@ -192,6 +196,7 @@ class VMManagementImpl implements VMManagement {
public native String[] getVmArguments0();
public native long getStartupTime();
private native long getUptime0();
public native int getAvailableProcessors();
// Compilation Subsystem

View File

@ -78,6 +78,7 @@ typedef enum {
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 */

View File

@ -200,6 +200,13 @@ Java_sun_management_VMManagementImpl_getStartupTime
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)

View File

@ -33,30 +33,34 @@ import java.lang.management.*;
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 @@ public class UpTime {
}
}
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 @@ public class UpTime {
System.out.println("Test passed.");
}
private static long System_milliTime() {
return System.nanoTime() / 1000000; // nanoseconds / milliseconds;
}
}
/*