8199375: [TESTBUG] Open source vm testbase monitoring tests
Reviewed-by: kvn, ihse, sspitsyn
/*
* Copyright (c) 2003, 2018, 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 nsk.monitoring.share;
import java.lang.management.*;
import javax.management.*;
import javax.management.openmbean.*;
import java.util.*;
import nsk.share.*;
/**
* <code>ThreadMonitor</code> class is a wrapper of <code>ThreadMXBean</code>.
* Depending on command line arguments, an instance of this class redirects
* invocations to the <code>ThreadMXBean</code> interface. If
* <code>-testMode="directly"</code> option is set, this instance directly
* invokes corresponding method of the <code>ThreadMXBean</code> interface.
* If <code>-testMode="server"</code> option is set it will make invocations
* via MBeanServer. If <code>-testMode="proxy"</code> option is set it will
* make invocations via MBeanServer proxy.
*
* @see ArgumentHandler
*/
public class ThreadMonitor extends Monitor {
// Names of the attributes of ThreadMXBean
private static final String GET_THREAD_INFO = "getThreadInfo";
private static final String GET_THREAD_CPU_TIME = "ThreadCpuTime";
private static final String ALL_THREAD_IDS = "AllThreadIds";
private static final String RESET_PEAK = "resetPeakThreadCount";
private static final String GET_PEAK_COUNT = "PeakThreadCount";
private static final String THREAD_COUNT = "ThreadCount";
private static final String FIND_THREADS = "findMonitorDeadlockedThreads";
private static final String IS_CURRENT = "CurrentThreadCpuTimeSupported";
private static final String IS_CPUTIME = "ThreadCpuTimeSupported";
private static final String IS_CONT_SUPP
= "ThreadContentionMonitoringSupported";
private static final String IS_CONT_ENAB
= "ThreadContentionMonitoringEnabled";
// An instance of ThreadMXBean
private static ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
// proxy instance
private ThreadMXBean proxyInstance;
// Internal trace level
private static final int TRACE_LEVEL = 10;
static {
Monitor.logPrefix = "ThreadMonitor> ";
}
/**
* Creates a new <code>ThreadMonitor</code> object.
*
* @param log <code>Log</code> object to print info to.
* @param argumentHandler <code>ArgumentHandler</code> object that saves
* all info about test's arguments.
*
*/
public ThreadMonitor(Log log, ArgumentHandler argumentHandler) {
super(log, argumentHandler);
}
/**
*
* Return a proxy instance for a platform
* {@link java.lang.management.ThreadMXBean
* <code>ThreadMXBean</code>} interface.
*
*/
synchronized ThreadMXBean getProxy() {
if (proxyInstance == null) {
// create proxy instance
try {
proxyInstance = (ThreadMXBean)
ManagementFactory.newPlatformMXBeanProxy(
getMBeanServer(),
ManagementFactory.THREAD_MXBEAN_NAME,
ThreadMXBean.class
);
} catch (Exception e) {
throw new Failure(e);
}
}
return proxyInstance;
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#getAllThreadIds()
* <code>ThreadMXBean.getAllThreadIds()</code>}.
*
* @return an array of <code>long</code>, each is a thread ID.
*/
public long[] getAllThreadIds() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
logger.trace(TRACE_LEVEL,"[getAllThreadIds] getAllThreadIds()"
+ " directly invoked");
return mbean.getAllThreadIds();
case SERVER_MODE:
logger.trace(TRACE_LEVEL,"[getAllThreadIds] getAllThreadIds()"
+ " invoked through MBeanServer");
return getLongArrayAttribute(mbeanObjectName, ALL_THREAD_IDS);
case PROXY_MODE:
logger.trace(TRACE_LEVEL,"[getAllThreadIds] getAllThreadIds()"
+ " invoked through MBeanServer proxy");
return getProxy().getAllThreadIds();
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#getThreadInfo
* <code>ThreadMXBean.getThreadInfo()</code>}.
*
* @param id the thread ID of the thread.
* @param maxDepth the maximum number of entries in the stack trace to
* be dumped. <code>Integer.MAX_VALUE</code> could be used to request
* entire stack to be dumped.
*
* @return A <code>ThreadInfo</code> of the thread of the given ID.
* <code>null</code> if the thread of the given ID is not alive
* or it does not exist
*/
public ThreadInfo getThreadInfo(long id, int maxDepth) {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
logger.trace(TRACE_LEVEL, "[getThreadInfo] getThreadInfo(long, "
+ "int) directly invoked");
return mbean.getThreadInfo(id, maxDepth);
case SERVER_MODE:
Object[] params = {new Long(id), new Integer(maxDepth)};
String[] signature = {"long", "int"};
try {
logger.trace(TRACE_LEVEL, "[getThreadInfo] getThreadInfo(long, "
+ "int) invoked through MBeanServer");
Object value = getMBeanServer().invoke(mbeanObjectName,
GET_THREAD_INFO,
params, signature);
if (value instanceof ThreadInfo)
return (ThreadInfo) value;
else {
CompositeData data = (CompositeData) value;
return ThreadInfo.from(data);
}
} catch (Exception e) {
e.printStackTrace();
throw new Failure(e);
}
case PROXY_MODE:
logger.trace(TRACE_LEVEL, "[getThreadInfo] getThreadInfo(long, "
+ "int) invoked through MBeanServer proxy");
return getProxy().getThreadInfo(id, maxDepth);
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#isCurrentThreadCpuTimeSupported()
* <code>ThreadMXBean.isCurrentThreadCpuTimeSupported()</code>}.
*
* @return <code>true</code>, if the JVM supports CPU time measurement for
* current thread, <code>false</code> otherwise.
*/
public boolean isCurrentThreadCpuTimeSupported() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.isCurrentThreadCpuTimeSupported();
case SERVER_MODE:
return getBooleanAttribute(mbeanObjectName, IS_CURRENT);
case PROXY_MODE:
return getProxy().isCurrentThreadCpuTimeSupported();
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#isThreadCpuTimeSupported()
* <code>ThreadMXBean.isThreadCpuTimeSupported()</code>}.
*
* @return <code>true</code>, if the JVM supports CPU time measurement for
* any threads, <code>false</code> otherwise.
*/
public boolean isThreadCpuTimeSupported() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.isThreadCpuTimeSupported();
case SERVER_MODE:
return getBooleanAttribute(mbeanObjectName, IS_CPUTIME);
case PROXY_MODE:
return getProxy().isThreadCpuTimeSupported();
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#isThreadContentionMonitoringSupported()
* <code>ThreadMXBean.isThreadContentionMonitoringSupported()</code>}.
*
* @return <code>true</code>, if the JVM supports thread contantion
* monitoring, <code>false</code> otherwise.
*/
public boolean isThreadContentionMonitoringSupported() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.isThreadContentionMonitoringSupported();
case SERVER_MODE:
return getBooleanAttribute(mbeanObjectName, IS_CONT_SUPP);
case PROXY_MODE:
return getProxy().isThreadContentionMonitoringSupported();
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#setThreadContentionMonitoringEnabled
* <code>ThreadMXBean.setThreadContentionMonitoringEnabled()</code>}.
*
* @param enable <code>true</code> to enable, <code>false</code> to disable.
*/
public void setThreadContentionMonitoringEnabled(boolean enable) {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
mbean.setThreadContentionMonitoringEnabled(enable);
break;
case SERVER_MODE:
setBooleanAttribute(mbeanObjectName, IS_CONT_ENAB, enable);
break;
case PROXY_MODE:
getProxy().setThreadContentionMonitoringEnabled(enable);
break;
default:
throw new TestBug("Unknown testMode " + mode);
}
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#getThreadCpuTime
* <code>ThreadMXBean.getThreadCpuTime()</code>}.
*
* @param id the id of a thread
*
* @return the CPU time for a thread of the specified ID, if the thread
* existsand is alive and CPU time measurement is enabled, -1
* otherwise.
*/
public long getThreadCpuTime(long id) {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.getThreadCpuTime(id);
case SERVER_MODE:
Object[] params = {new Long(id)};
String[] signature = {"long"};
try {
Long l = (Long) getMBeanServer().invoke(mbeanObjectName,
GET_THREAD_CPU_TIME,
params, signature);
return l.longValue();
} catch (Exception e) {
e.printStackTrace();
throw new Failure(e);
}
case PROXY_MODE:
return getProxy().getThreadCpuTime(id);
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#getThreadCount()
* <code>ThreadMXBean.getThreadCount()</code>}.
*
* @return the current number of live threads.
*/
public int getThreadCount() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.getThreadCount();
case SERVER_MODE:
return getIntAttribute(mbeanObjectName, THREAD_COUNT);
case PROXY_MODE:
return getProxy().getThreadCount();
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#getPeakThreadCount()
* <code>ThreadMXBean.getPeakThreadCount()</code>}.
*
* @return the peak live thrad count.
*/
public int getPeakThreadCount() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.getPeakThreadCount();
case SERVER_MODE:
return getIntAttribute(mbeanObjectName, GET_PEAK_COUNT);
case PROXY_MODE:
return getProxy().getPeakThreadCount();
}
throw new TestBug("Unknown testMode " + mode);
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#resetPeakThreadCount()
* <code>ThreadMXBean.resetPeakThreadCount()</code>}.
*/
public void resetPeakThreadCount() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
mbean.resetPeakThreadCount();
break;
case SERVER_MODE:
try {
getMBeanServer().invoke(mbeanObjectName, RESET_PEAK, null, null);
} catch (Exception e) {
e.printStackTrace(logger.getOutStream());
throw new Failure(e);
}
break;
case PROXY_MODE:
getProxy().resetPeakThreadCount();
break;
default:
throw new TestBug("Unknown testMode " + mode);
}
}
/**
* Redirects the invocation to {@link
* java.lang.management.ThreadMXBean#findMonitorDeadlockedThreads
* <code>ThreadMXBean.findMonitorDeadlockedThreads()</code>}.
*
* @return an array of IDs of the reads that are monitor deadlocked, if any;
* <code>null</code> otherwise.
*/
public long[] findMonitorDeadlockedThreads() {
int mode = getTestMode();
switch (mode) {
case DIRECTLY_MODE:
return mbean.findMonitorDeadlockedThreads();
case SERVER_MODE:
try {
Object o = (Object) getMBeanServer().invoke(mbeanObjectName,
FIND_THREADS, null, null);
return (long[]) o;
} catch (Exception e) {
e.printStackTrace(logger.getOutStream());
throw new Failure(e);
}
case PROXY_MODE:
return getProxy().findMonitorDeadlockedThreads();
}
throw new TestBug("Unknown testMode " + mode);
}
} // ThreadMonitor