Skip to content

Commit

Permalink
vjtop 当JMX不能响应时(如FullGC中),尽量打印从其他渠道获取的信息 #104
Browse files Browse the repository at this point in the history
进一步优化PerfData的使用

fix Safepoint asyncTime的bug
  • Loading branch information
calvin1978 committed Aug 21, 2018
1 parent 6009176 commit bd84a69
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 133 deletions.
2 changes: 1 addition & 1 deletion vjtop/src/main/java/com/vip/vjtools/vjtop/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class Utils {
private static final long GB_SIZE = MB_SIZE * 1024;
private static final long TB_SIZE = GB_SIZE * 1024;

private static final String[] RED_ANSI = new String[] { "\033[31m\033[01m", "\033[0m" };
public static final String[] RED_ANSI = new String[] { "\033[31m\033[01m", "\033[0m" };
private static final String[] YELLOW_ANSI = new String[] { "\033[33m\033[01m", "\033[0m" };
private static final String[] NORMAL_ANSI = new String[] { "", "" };
public static boolean isWindows = System.getProperty("os.name").toLowerCase(Locale.US).contains("windows");
Expand Down
9 changes: 7 additions & 2 deletions vjtop/src/main/java/com/vip/vjtools/vjtop/VJTop.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ public static void main(String[] args) {

VMInfo vminfo = VMInfo.processNewVM(pid, jmxHostAndPort);
if (vminfo.state != VMInfoState.ATTACHED) {
System.out.println("\nERROR: Could not attach to process, see the solution in README\n");
System.out.println("\n" + Utils.RED_ANSI[0]
+ "ERROR: Could not attach to process, see the solution in README" + Utils.RED_ANSI[1]);
return;
}

Expand Down Expand Up @@ -157,6 +158,10 @@ private void run(VMDetailView view) throws Exception {

view.printView();

if (view.shouldExit()) {
break;
}

System.out.flush();

if (maxIterations > 0 && iterations >= maxIterations) {
Expand All @@ -174,7 +179,7 @@ private void run(VMDetailView view) throws Exception {
System.out.flush();
} catch (NoClassDefFoundError e) {
e.printStackTrace(System.out);
System.out.println("ERROR: Some JDK classes cannot be found.");
System.out.println(Utils.RED_ANSI[0] + "ERROR: Some JDK classes cannot be found." + Utils.RED_ANSI[1]);
System.out.println(" Please check if the JAVA_HOME environment variable has been set to a JDK path.");
System.out.println("");
System.out.flush();
Expand Down
82 changes: 50 additions & 32 deletions vjtop/src/main/java/com/vip/vjtools/vjtop/VMDetailView.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.Map;

import com.sun.management.OperatingSystemMXBean;
import com.vip.vjtools.vjtop.VMInfo.VMInfoState;

@SuppressWarnings("restriction")
public class VMDetailView {
Expand Down Expand Up @@ -43,7 +42,7 @@ public class VMDetailView {

public VMDetailView(VMInfo vmInfo, DetailMode mode, Integer width, Integer interval) throws Exception {
this.vmInfo = vmInfo;
this.warning = vmInfo.warning;
this.warning = vmInfo.warningRule;
this.mode = mode;
setWidth(width);
setInterval(interval);
Expand All @@ -67,34 +66,46 @@ public void printView() throws Exception {
// 打印进程级别内容
printJvmInfo();

// JMX更新失败,不打印后续一定需要JMX获取的数据
if (!vmInfo.isJmxStateOk()) {
System.out.print("\n " + Utils.RED_ANSI[0] + "ERROR: Could not fetch data via JMX");
if (!vmInfo.currentGcCause.equals("No GC")) {
System.out.println(" - Process is doing GC, cause is " + vmInfo.currentGcCause + Utils.RED_ANSI[1]);
} else {
System.out.println(" - Process terminated?" + Utils.RED_ANSI[1]);
}
return;
}

// 打印线程级别内容
if (mode.isCpuMode) {
printTopCpuThreads(mode);
} else {
printTopMemoryThreads(mode);
try {
if (mode.isCpuMode) {
printTopCpuThreads(mode);
} else {
printTopMemoryThreads(mode);
}
} catch (Exception e) {
System.out.println("\n" + Utils.RED_ANSI[0]
+ "ERROR: Exception happen when fetch thread information via JMX" + Utils.RED_ANSI[1]);
}

if (isDebug) {
// 打印vjtop自身消耗
printIterationCost(iterationStartTime, iterationStartCpu);
}

if (displayCommandHints) {
System.out.print(" Input command (h for help):");
}
}

private boolean checkState() {
if (vmInfo.state == VMInfoState.ATTACHED_UPDATE_ERROR) {
System.out.println("ERROR: Could not fetch data - Process terminated?");
return false;
}

if (vmInfo.state != VMInfo.VMInfoState.ATTACHED) {
System.out.println("ERROR: Could not attach to process. ");
if (vmInfo.state != VMInfo.VMInfoState.ATTACHED && vmInfo.state != VMInfo.VMInfoState.ATTACHED_UPDATE_ERROR) {
System.out.println(
"\n" + Utils.RED_ANSI[0] + "ERROR: Could not attach to process, exit now." + Utils.RED_ANSI[1]);
exit();
return false;
}

return true;
}

Expand All @@ -121,7 +132,7 @@ private void printJvmInfo() {
}
System.out.println();

System.out.printf(" THREAD: %s active, %d daemon, %s peak, %s new",
System.out.printf(" THREAD: %s live, %d daemon, %s peak, %s new",
Utils.toColor(vmInfo.threadActive, warning.thread), vmInfo.threadDaemon, vmInfo.threadPeak,
Utils.toColor(vmInfo.threadNew.delta, warning.newThread));

Expand Down Expand Up @@ -167,7 +178,7 @@ private void printTopCpuThreads(DetailMode mode) throws IOException {
return;
}

long threadsHaveValue = 0;
long noteableThreads = 0;

long tids[] = vmInfo.getThreadMXBean().getAllThreadIds();
int mapSize = tids.length * 2;
Expand All @@ -184,8 +195,8 @@ private void printTopCpuThreads(DetailMode mode) throws IOException {
long deltaAllThreadCpu = 0;
long deltaAllThreadSysCpu = 0;

// 过滤CPU占用太少的线程,每秒0.1%CPU (1ms)
minDeltaCpuTime = (vmInfo.upTimeMills.delta / 1000) * Utils.NANOS_TO_MILLS;
// 过滤CPU占用太少的线程,每秒0.05%CPU (0.5ms cpu time)
minDeltaCpuTime = (vmInfo.upTimeMills.delta * Utils.NANOS_TO_MILLS / 2000);

// 计算本次CPU Time
// 此算法第一次不会显示任何数据,保证每次显示都只显示区间内数据
Expand Down Expand Up @@ -240,18 +251,22 @@ private void printTopCpuThreads(DetailMode mode) throws IOException {
long[] topTidArray;
if (mode == DetailMode.cpu) {
topTidArray = Utils.sortAndFilterThreadIdsByValue(threadCpuDeltaTimes, threadLimit);
threadsHaveValue = threadCpuDeltaTimes.size();
noteableThreads = threadCpuDeltaTimes.size();
} else if (mode == DetailMode.syscpu) {
topTidArray = Utils.sortAndFilterThreadIdsByValue(threadSysCpuDeltaTimes, threadLimit);
threadsHaveValue = threadSysCpuDeltaTimes.size();
noteableThreads = threadSysCpuDeltaTimes.size();
} else if (mode == DetailMode.totalcpu) {
topTidArray = Utils.sortAndFilterThreadIdsByValue(threadCpuTotalTimes, threadLimit);
threadsHaveValue = threadCpuTotalTimes.size();
noteableThreads = threadCpuTotalTimes.size();
} else if (mode == DetailMode.totalsyscpu) {
topTidArray = Utils.sortAndFilterThreadIdsByValue(threadSysCpuTotalTimes, threadLimit);
threadsHaveValue = threadSysCpuTotalTimes.size();
noteableThreads = threadSysCpuTotalTimes.size();
} else {
throw new RuntimeException("unkown mode");
throw new RuntimeException("unkown mode:" + mode);
}

if (noteableThreads == 0) {
System.out.printf("%n -Every thread use cpu lower than 0.05%%-%n");
}

// 获得threadInfo
Expand Down Expand Up @@ -293,10 +308,9 @@ private void printTopCpuThreads(DetailMode mode) throws IOException {
double deltaAllThreadSysCpuLoad = Utils.calcLoad(deltaAllThreadSysCpu / Utils.NANOS_TO_MILLS,
vmInfo.upTimeMills.delta);

System.out.printf(
"%n Total : %5.2f%% cpu(user=%5.2f%%, sys=%5.2f%%) by %d notable threads(which cpu>0.1%%)%n",
System.out.printf("%n Total : %5.2f%% cpu(user=%5.2f%%, sys=%5.2f%%) by %d active threads(which cpu>0.05%%)%n",
deltaAllThreadCpuLoad, deltaAllThreadCpuLoad - deltaAllThreadSysCpuLoad, deltaAllThreadSysCpuLoad,
threadsHaveValue);
noteableThreads);

System.out.printf(" Setting: top %d threads order by %s%s, flush every %ds%n", threadLimit,
mode.toString().toUpperCase(), threadNameFilter == null ? "" : " filter by " + threadNameFilter,
Expand All @@ -322,13 +336,13 @@ private void printTopMemoryThreads(DetailMode mode) throws IOException {
long totalDeltaBytes = 0;
long totalBytes = 0;

long threadsHaveValue = 0;
long noteableThreads = 0;

// 批量获取内存分配
long[] threadMemoryTotalBytesArray = vmInfo.getThreadMXBean().getThreadAllocatedBytes(tids);

// 过滤太少的线程,每秒小于1k
minDeltaMemory = (vmInfo.upTimeMills.delta / 1000) * 1024;
minDeltaMemory = vmInfo.upTimeMills.delta * 1024 / 1000;

// 此算法第一次不会显示任何数据,保证每次显示都只显示区间内数据
for (int i = 0; i < tids.length; i++) {
Expand Down Expand Up @@ -367,10 +381,14 @@ private void printTopMemoryThreads(DetailMode mode) throws IOException {
long[] topTidArray;
if (mode == DetailMode.memory) {
topTidArray = Utils.sortAndFilterThreadIdsByValue(threadMemoryDeltaBytesMap, threadLimit);
threadsHaveValue = threadMemoryDeltaBytesMap.size();
noteableThreads = threadMemoryDeltaBytesMap.size();
} else {
topTidArray = Utils.sortAndFilterThreadIdsByValue(threadMemoryTotalBytesMap, threadLimit);
threadsHaveValue = threadMemoryTotalBytesMap.size();
noteableThreads = threadMemoryTotalBytesMap.size();
}

if (noteableThreads == 0) {
System.out.printf("%n -Every thread allocate memory slower than 1k/s-%n");
}

ThreadInfo[] threadInfos = vmInfo.getThreadMXBean().getThreadInfo(topTidArray);
Expand Down Expand Up @@ -398,8 +416,8 @@ private void printTopMemoryThreads(DetailMode mode) throws IOException {
}

// 打印线程汇总信息,这里因为最后单位是精确到秒,所以bytes除以毫秒以后要乘以1000才是按秒统计
System.out.printf("%n Total : %5s/s memory allocated by %d noteable threads(which >1k/s)%n",
Utils.toFixLengthSizeUnit((totalDeltaBytes * 1000) / vmInfo.upTimeMills.delta), threadsHaveValue);
System.out.printf("%n Total : %5s/s memory allocated by %d active threads(which >1k/s)%n",
Utils.toFixLengthSizeUnit((totalDeltaBytes * 1000) / vmInfo.upTimeMills.delta), noteableThreads);

System.out.printf(" Setting: top %d threads order by %s%s, flush every %ds%n", threadLimit,
mode.toString().toUpperCase(), threadNameFilter == null ? "" : " filter by " + threadNameFilter,
Expand Down
Loading

0 comments on commit bd84a69

Please sign in to comment.