/**
* Copyright 2013 Alexey Ragozin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gridkit.jvmtool.cmd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.management.MBeanServerConnection;
import org.gridkit.jvmtool.GlobHelper;
import org.gridkit.jvmtool.JmxConnectionInfo;
import org.gridkit.jvmtool.MBeanCpuUsageReporter;
import org.gridkit.jvmtool.PerfCounterGcCpuUsageMonitor;
import org.gridkit.jvmtool.PerfCounterSafePointMonitor;
import org.gridkit.jvmtool.cli.CommandLauncher;
import org.gridkit.jvmtool.cli.TimeIntervalConverter;
import org.gridkit.jvmtool.cli.CommandLauncher.CmdRef;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.beust.jcommander.ParametersDelegate;
/**
* Thread top command.
*
* @author Alexey Ragozin (alexey.ragozin@gmail.com)
*/
public class ThreadTopCmd implements CmdRef {
@Override
public String getCommandName() {
return "ttop";
}
@Override
public Runnable newCommand(CommandLauncher host) {
return new TTop(host);
}
@Parameters(commandDescription = "[Thread Top] Displays threads from JVM process")
public static class TTop implements Runnable {
@ParametersDelegate
private CommandLauncher host;
@Parameter(names = {"-ri", "--report-interval"}, converter = TimeIntervalConverter.class, description = "Interval between CPU usage reports")
private long reportIntervalMS = TimeUnit.SECONDS.toMillis(10);
@Parameter(names = {"-si", "--sampler-interval"}, converter = TimeIntervalConverter.class, description = "Interval between polling MBeans")
private long samplerIntervalMS = 500;
@Parameter(names = {"-n", "--top-number"}, description = "Number of threads to show")
private int topNumber = 20;
@Parameter(names = {"-o", "--order"}, variableArity = true, description = "Sort order. Value tags: CPU, USER, SYS, ALLOC, NAME")
private List<String> sortOrder = new ArrayList<String>(Arrays.asList("CPU"));
@Parameter(names = {"-f", "--filter"}, description = "Wild card expression to filter threads by name")
private String threadFilter;
@ParametersDelegate
private JmxConnectionInfo connInfo;
public TTop(CommandLauncher host) {
this.host = host;
this.connInfo = new JmxConnectionInfo(host);
}
@Override
public void run() {
try {
MBeanServerConnection mserver = connInfo.getMServer();
final MBeanCpuUsageReporter tmon = new MBeanCpuUsageReporter(mserver);
if (connInfo.getPID() != null) {
try {
long pid = connInfo.getPID();
PerfCounterGcCpuUsageMonitor pm = new PerfCounterGcCpuUsageMonitor(pid);
if (pm.isAvailable()) {
tmon.setGcCpuUsageMonitor(pm);
}
PerfCounterSafePointMonitor sm = new PerfCounterSafePointMonitor(pid);
if (sm.isAvailable()) {
tmon.setSafePointMonitor(sm);
}
// NativeThreadMonitor tm = PlatformProcessInfoProvider.createMonitor(pid);
// if (tm != null) {
// tmon.setNativeThreadMonitor(tm);
// }
}
catch(Exception e) {
// ignore
}
}
tmon.setTopLimit(topNumber);
if (threadFilter != null) {
tmon.setThreadFilter(GlobHelper.translate(threadFilter, "\0"));
}
if (sortOrder != null) {
Collections.reverse(sortOrder);
for(String tag: sortOrder) {
if ("SYS".equals(tag)) {
tmon.sortBySysCpu();
}
else if ("USER".equals(tag)){
tmon.sortByUserCpu();
}
else if ("CPU".equals(tag)){
tmon.sortByTotalCpu();
}
else if ("ALLOC".equals(tag)){
tmon.sortByAllocRate();
}
else if ("NAME".equals(tag)){
tmon.sortByThreadName();
}
else {
host.failAndPrintUsage("Invalid order option '" + tag + "'");
}
}
}
long deadline = System.currentTimeMillis() + Math.min(reportIntervalMS, 10 * samplerIntervalMS);
tmon.report();
System.out.println("Monitoring threads ...");
while(true) {
while(System.currentTimeMillis() < deadline) {
Thread.sleep(samplerIntervalMS);
tmon.probe();
}
deadline += reportIntervalMS;
System.out.println();
System.out.println(tmon.report());
System.out.println();
if (System.in.available() > 0) {
return;
}
}
} catch (Exception e) {
host.fail("Unexpected error: " + e.toString(), e);
}
}
}
}