/**
* jvmtop - java monitoring for the command-line
*
* Copyright (C) 2013 by Patric Rufflar. 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 program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.jvmtop.view;
import java.lang.management.ThreadInfo;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.jvmtop.monitor.VMInfo;
import com.jvmtop.monitor.VMInfoState;
import com.jvmtop.openjdk.tools.LocalVirtualMachine;
/**
* "detail" view, printing detail metrics of a specific jvm.
* Also printing the top threads (based on the current CPU usage)
*
* @author paru
*
*/
public class VMDetailView extends AbstractConsoleView
{
private VMInfo vmInfo_;
private boolean sortByTotalCPU_ = false;
private int numberOfDisplayedThreads_ = 10;
private int threadNameDisplayWidth_ = 30;
private boolean displayedThreadLimit_ = true;
//TODO: refactor
private Map<Long, Long> previousThreadCPUMillis = new HashMap<Long, Long>();
public VMDetailView(int vmid, Integer width) throws Exception
{
super(width);
LocalVirtualMachine localVirtualMachine = LocalVirtualMachine
.getLocalVirtualMachine(vmid);
vmInfo_ = VMInfo.processNewVM(localVirtualMachine, vmid);
}
public boolean isSortByTotalCPU()
{
return sortByTotalCPU_;
}
public void setSortByTotalCPU(boolean sortByTotalCPU)
{
sortByTotalCPU_ = sortByTotalCPU;
}
@Override
public void printView() throws Exception
{
vmInfo_.update();
if (vmInfo_.getState() == VMInfoState.ATTACHED_UPDATE_ERROR)
{
System.out
.println("ERROR: Could not fetch telemetries - Process terminated?");
exit();
return;
}
if (vmInfo_.getState() != VMInfoState.ATTACHED)
{
System.out.println("ERROR: Could not attach to process.");
exit();
return;
}
Map<String, String> properties = vmInfo_.getSystemProperties();
String command = properties.get("sun.java.command");
if (command != null)
{
String[] commandArray = command.split(" ");
List<String> commandList = Arrays.asList(commandArray);
commandList = commandList.subList(1, commandList.size());
System.out.printf(" PID %d: %s %n", vmInfo_.getId(), commandArray[0]);
String argJoin = join(commandList, " ");
if (argJoin.length() > 67)
{
System.out.printf(" ARGS: %s[...]%n", leftStr(argJoin, 67));
}
else
{
System.out.printf(" ARGS: %s%n", argJoin);
}
}
else
{
System.out.printf(" PID %d: %n", vmInfo_.getId());
System.out.printf(" ARGS: [UNKNOWN] %n");
}
String join = join(vmInfo_.getRuntimeMXBean().getInputArguments(), " ");
if (join.length() > 65)
{
System.out.printf(" VMARGS: %s[...]%n", leftStr(join, 65));
}
else
{
System.out.printf(" VMARGS: %s%n", join);
}
System.out.printf(" VM: %s %s %s%n", properties.get("java.vendor"),
properties.get("java.vm.name"), properties.get("java.version"));
System.out.printf(
" UP: %-7s #THR: %-4d #THRPEAK: %-4d #THRCREATED: %-4d USER: %-12s%n",
toHHMM(vmInfo_.getRuntimeMXBean().getUptime()), vmInfo_
.getThreadCount(), vmInfo_.getThreadMXBean().getPeakThreadCount(),
vmInfo_.getThreadMXBean().getTotalStartedThreadCount(), vmInfo_
.getOSUser());
System.out.printf(
" GC-Time: %-7s #GC-Runs: %-8d #TotalLoadedClasses: %-8d%n",
toHHMM(vmInfo_.getGcTime()), vmInfo_.getGcCount(),
vmInfo_.getTotalLoadedClassCount());
System.out.printf(
" CPU: %5.2f%% GC: %5.2f%% HEAP:%5s /%5s NONHEAP:%5s /%5s%n",
vmInfo_.getCpuLoad() * 100, vmInfo_.getGcLoad() * 100,
toMB(vmInfo_.getHeapUsed()), toMB(vmInfo_.getHeapMax()),
toMB(vmInfo_.getNonHeapUsed()), toMB(vmInfo_.getNonHeapMax()));
System.out.println();
printTopThreads();
}
/**
* @throws Exception
*/
private void printTopThreads() throws Exception
{
System.out.printf(" %6s %-" + threadNameDisplayWidth_
+ "s %13s %8s %8s %5s %n", "TID", "NAME", "STATE", "CPU",
"TOTALCPU", "BLOCKEDBY");
if (vmInfo_.getThreadMXBean().isThreadCpuTimeSupported())
{
//TODO: move this into VMInfo?
Map<Long, Long> newThreadCPUMillis = new HashMap<Long, Long>();
Map<Long, Long> cpuTimeMap = new TreeMap<Long, Long>();
for (Long tid : vmInfo_.getThreadMXBean().getAllThreadIds())
{
long threadCpuTime = vmInfo_.getThreadMXBean().getThreadCpuTime(tid);
long deltaThreadCpuTime = 0;
if (previousThreadCPUMillis.containsKey(tid))
{
deltaThreadCpuTime = threadCpuTime - previousThreadCPUMillis.get(tid);
cpuTimeMap.put(tid, deltaThreadCpuTime);
}
newThreadCPUMillis.put(tid, threadCpuTime);
}
cpuTimeMap = sortByValue(cpuTimeMap, true);
int displayedThreads = 0;
for (Long tid : cpuTimeMap.keySet())
{
ThreadInfo info = vmInfo_.getThreadMXBean().getThreadInfo(tid);
displayedThreads++;
if (displayedThreads > numberOfDisplayedThreads_
&& displayedThreadLimit_)
{
break;
}
if (info != null)
{
System.out.printf(
" %6d %-" + threadNameDisplayWidth_
+ "s %13s %5.2f%% %5.2f%% %5s %n",
tid,
leftStr(info.getThreadName(), threadNameDisplayWidth_),
info.getThreadState(),
getThreadCPUUtilization(cpuTimeMap.get(tid),
vmInfo_.getDeltaUptime()),
getThreadCPUUtilization(vmInfo_.getThreadMXBean()
.getThreadCpuTime(tid), vmInfo_.getProxyClient()
.getProcessCpuTime(), 1), getBlockedThread(info));
}
}
if (newThreadCPUMillis.size() >= numberOfDisplayedThreads_
&& displayedThreadLimit_)
{
System.out.printf(
" Note: Only top %d threads (according cpu load) are shown!",
numberOfDisplayedThreads_);
}
previousThreadCPUMillis = newThreadCPUMillis;
}
else
{
System.out
.printf("%n -Thread CPU telemetries are not available on the monitored jvm/platform-%n");
}
}
private String getBlockedThread(ThreadInfo info)
{
if (info.getLockOwnerId() >= 0)
{
return "" + info.getLockOwnerId();
}
else
{
return "";
}
}
public int getNumberOfDisplayedThreads()
{
return numberOfDisplayedThreads_;
}
public void setNumberOfDisplayedThreads(int numberOfDisplayedThreads)
{
numberOfDisplayedThreads_ = numberOfDisplayedThreads;
}
public boolean isDisplayedThreadLimit()
{
return displayedThreadLimit_;
}
public void setDisplayedThreadLimit(boolean displayedThreadLimit)
{
displayedThreadLimit_ = displayedThreadLimit;
}
public int getThreadNameDisplayWidth()
{
return threadNameDisplayWidth_;
}
public void setThreadNameDisplayWidth(int threadNameDisplayWidth_)
{
this.threadNameDisplayWidth_ = threadNameDisplayWidth_;
}
private double getThreadCPUUtilization(long deltaThreadCpuTime, long totalTime)
{
return getThreadCPUUtilization(deltaThreadCpuTime, totalTime, 1000 * 1000);
}
private double getThreadCPUUtilization(long deltaThreadCpuTime,
long totalTime, double factor)
{
if (totalTime == 0)
{
return 0;
}
return deltaThreadCpuTime / factor / totalTime * 100d;
}
}