transform command: jvm, improve MEMORY section

pull/1306/head
gongdewei 5 years ago
parent 25a8ba9f4f
commit e629ce72c2

@ -0,0 +1,46 @@
package com.taobao.arthas.core.command.model;
/**
* Key/value/desc
* @author gongdewei 2020/4/24
*/
public class JvmItemVO {
private String name;
private Object value;
private String desc;
public JvmItemVO(String name, Object value, String desc) {
this.name = name;
this.value = value;
this.desc = desc;
}
public JvmItemVO(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}

@ -0,0 +1,48 @@
package com.taobao.arthas.core.command.model;
import java.util.*;
/**
* Model of 'jvm' command
*
* @author gongdewei 2020/4/24
*/
public class JvmModel extends ResultModel {
private Map<String, List<JvmItemVO>> jvmInfo;
public JvmModel() {
jvmInfo = Collections.synchronizedMap(new LinkedHashMap<String, List<JvmItemVO>>());
}
@Override
public String getType() {
return "jvm";
}
public JvmModel addItem(String group, String name, Object value) {
this.addItem(group, name, value, null);
return this;
}
public JvmModel addItem(String group, String name, Object value, String desc) {
this.group(group).add(new JvmItemVO(name, value, desc));
return this;
}
public List<JvmItemVO> group(String group) {
synchronized (this) {
List<JvmItemVO> list = jvmInfo.get(group);
if (list == null) {
list = new ArrayList<JvmItemVO>();
jvmInfo.put(group, list);
}
return list;
}
}
public Map<String, List<JvmItemVO>> getJvmInfo() {
return jvmInfo;
}
}

@ -1,25 +1,21 @@
package com.taobao.arthas.core.command.monitor200;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.GcInfoVO;
import com.taobao.arthas.core.command.model.JvmModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.util.affect.RowAffect;
import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Summary;
import com.taobao.text.Decoration;
import com.taobao.text.ui.Element;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.lang.management.*;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import static com.taobao.text.ui.Element.label;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* JVM info command
@ -43,50 +39,41 @@ public class JvmCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
RowAffect affect = new RowAffect();
TableElement table = new TableElement(2, 5).leftCellPadding(1).rightCellPadding(1);
table.row(true, label("RUNTIME").style(Decoration.bold.bold()));
drawRuntimeTable(table);
table.row("", "");
table.row(true, label("CLASS-LOADING").style(Decoration.bold.bold()));
drawClassLoadingTable(table);
table.row("", "");
table.row(true, label("COMPILATION").style(Decoration.bold.bold()));
drawCompilationTable(table);
JvmModel jvmModel = new JvmModel();
addRuntimeInfo(jvmModel);
addClassLoading(jvmModel);
addCompilation(jvmModel);
if (!garbageCollectorMXBeans.isEmpty()) {
table.row("", "");
table.row(true, label("GARBAGE-COLLECTORS").style(Decoration.bold.bold()));
drawGarbageCollectorsTable(table);
addGarbageCollectors(jvmModel);
}
if (!memoryManagerMXBeans.isEmpty()) {
table.row("", "");
table.row(true, label("MEMORY-MANAGERS").style(Decoration.bold.bold()));
drawMemoryManagersTable(table);
addMemoryManagers(jvmModel);
}
table.row("", "");
table.row(true, label("MEMORY").style(Decoration.bold.bold()));
drawMemoryTable(table);
table.row("", "");
table.row(true, label("OPERATING-SYSTEM").style(Decoration.bold.bold()));
drawOperatingSystemMXBeanTable(table);
table.row("", "");
table.row(true, label("THREAD").style(Decoration.bold.bold()));
drawThreadTable(table);
table.row("", "");
table.row(true, label("FILE-DESCRIPTOR").style(Decoration.bold.bold()));
drawFileDescriptorTable(table);
process.write(RenderUtil.render(table, process.width()));
process.write(affect.toString()).write("\n");
addMemory(jvmModel);
addOperatingSystem(jvmModel);
addThread(jvmModel);
addFileDescriptor(jvmModel);
process.appendResult(jvmModel);
process.end();
}
private void drawFileDescriptorTable(TableElement table) {
table.row("MAX-FILE-DESCRIPTOR-COUNT", "" + invokeFileDescriptor(operatingSystemMXBean, "getMaxFileDescriptorCount"))
.row("OPEN-FILE-DESCRIPTOR-COUNT", "" + invokeFileDescriptor(operatingSystemMXBean, "getOpenFileDescriptorCount"));
private void addFileDescriptor(JvmModel jvmModel) {
String group = "FILE-DESCRIPTOR";
jvmModel.addItem(group,"MAX-FILE-DESCRIPTOR-COUNT", invokeFileDescriptor(operatingSystemMXBean, "getMaxFileDescriptorCount"))
.addItem(group,"OPEN-FILE-DESCRIPTOR-COUNT", invokeFileDescriptor(operatingSystemMXBean, "getOpenFileDescriptorCount"));
}
private long invokeFileDescriptor(OperatingSystemMXBean os, String name) {
try {
final Method method = os.getClass().getDeclaredMethod(name);
@ -96,137 +83,111 @@ public class JvmCommand extends AnnotatedCommand {
return -1;
}
}
private String toCol(Collection<String> strings) {
final StringBuilder colSB = new StringBuilder();
if (strings.isEmpty()) {
colSB.append("[]");
} else {
for (String str : strings) {
colSB.append(str).append("\n");
}
}
return colSB.toString();
}
private String toCol(String... stringArray) {
final StringBuilder colSB = new StringBuilder();
if (null == stringArray
|| stringArray.length == 0) {
colSB.append("[]");
} else {
for (String str : stringArray) {
colSB.append(str).append("\n");
}
}
return colSB.toString();
}
private Element drawRuntimeTable(TableElement table) {
private void addRuntimeInfo(JvmModel jvmModel) {
String bootClassPath = "";
try {
bootClassPath = runtimeMXBean.getBootClassPath();
} catch (Exception e) {
// under jdk9 will throw UnsupportedOperationException, ignore
}
table.row("MACHINE-NAME", runtimeMXBean.getName())
.row("JVM-START-TIME", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(runtimeMXBean.getStartTime())))
.row("MANAGEMENT-SPEC-VERSION", runtimeMXBean.getManagementSpecVersion())
.row("SPEC-NAME", runtimeMXBean.getSpecName())
.row("SPEC-VENDOR", runtimeMXBean.getSpecVendor())
.row("SPEC-VERSION", runtimeMXBean.getSpecVersion())
.row("VM-NAME", runtimeMXBean.getVmName())
.row("VM-VENDOR", runtimeMXBean.getVmVendor())
.row("VM-VERSION", runtimeMXBean.getVmVersion())
.row("INPUT-ARGUMENTS", toCol(runtimeMXBean.getInputArguments()))
.row("CLASS-PATH", runtimeMXBean.getClassPath())
.row("BOOT-CLASS-PATH", bootClassPath)
.row("LIBRARY-PATH", runtimeMXBean.getLibraryPath());
return table;
String group = "RUNTIME";
jvmModel.addItem(group,"MACHINE-NAME", runtimeMXBean.getName());
jvmModel.addItem(group, "JVM-START-TIME", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(runtimeMXBean.getStartTime())));
jvmModel.addItem(group, "MANAGEMENT-SPEC-VERSION", runtimeMXBean.getManagementSpecVersion());
jvmModel.addItem(group, "SPEC-NAME", runtimeMXBean.getSpecName());
jvmModel.addItem(group, "SPEC-VENDOR", runtimeMXBean.getSpecVendor());
jvmModel.addItem(group, "SPEC-VERSION", runtimeMXBean.getSpecVersion());
jvmModel.addItem(group, "VM-NAME", runtimeMXBean.getVmName());
jvmModel.addItem(group, "VM-VENDOR", runtimeMXBean.getVmVendor());
jvmModel.addItem(group, "VM-VERSION", runtimeMXBean.getVmVersion());
jvmModel.addItem(group, "INPUT-ARGUMENTS", runtimeMXBean.getInputArguments());
jvmModel.addItem(group, "CLASS-PATH", runtimeMXBean.getClassPath());
jvmModel.addItem(group, "BOOT-CLASS-PATH", bootClassPath);
jvmModel.addItem(group, "LIBRARY-PATH", runtimeMXBean.getLibraryPath());
}
private Element drawClassLoadingTable(TableElement table) {
table.row("LOADED-CLASS-COUNT", "" + classLoadingMXBean.getLoadedClassCount())
.row("TOTAL-LOADED-CLASS-COUNT", "" + classLoadingMXBean.getTotalLoadedClassCount())
.row("UNLOADED-CLASS-COUNT", "" + classLoadingMXBean.getUnloadedClassCount())
.row("IS-VERBOSE", "" + classLoadingMXBean.isVerbose());
return table;
private void addClassLoading(JvmModel jvmModel) {
String group = "CLASS-LOADING";
jvmModel.addItem(group, "LOADED-CLASS-COUNT", classLoadingMXBean.getLoadedClassCount());
jvmModel.addItem(group, "TOTAL-LOADED-CLASS-COUNT", classLoadingMXBean.getTotalLoadedClassCount());
jvmModel.addItem(group, "UNLOADED-CLASS-COUNT", classLoadingMXBean.getUnloadedClassCount());
jvmModel.addItem(group, "IS-VERBOSE", classLoadingMXBean.isVerbose());
}
private Element drawCompilationTable(TableElement table) {
table.row("NAME", compilationMXBean.getName());
private void addCompilation(JvmModel jvmModel) {
String group = "COMPILATION";
jvmModel.addItem(group, "NAME", compilationMXBean.getName());
if (compilationMXBean.isCompilationTimeMonitoringSupported()) {
table.row("TOTAL-COMPILE-TIME", compilationMXBean.getTotalCompilationTime() + "(ms)");
jvmModel.addItem(group, "TOTAL-COMPILE-TIME", compilationMXBean.getTotalCompilationTime(), "time (ms)");
}
return table;
}
private Element drawGarbageCollectorsTable(TableElement table) {
for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeans) {
table.row(garbageCollectorMXBean.getName() + "\n[count/time]",
garbageCollectorMXBean.getCollectionCount() + "/" + garbageCollectorMXBean.getCollectionTime() + "(ms)");
}
private void addGarbageCollectors(JvmModel jvmModel) {
String group = "GARBAGE-COLLECTORS";
for (GarbageCollectorMXBean gcMXBean : garbageCollectorMXBeans) {
Map<String, Object> gcInfo = new LinkedHashMap<String, Object>();
gcInfo.put("name", gcMXBean.getName());
gcInfo.put("collectionCount", gcMXBean.getCollectionCount());
gcInfo.put("collectionTime", gcMXBean.getCollectionTime());
return table;
jvmModel.addItem(group, gcMXBean.getName(), gcInfo, "count/time (ms)");
}
}
private Element drawMemoryManagersTable(TableElement table) {
private void addMemoryManagers(JvmModel jvmModel) {
String group = "MEMORY-MANAGERS";
for (final MemoryManagerMXBean memoryManagerMXBean : memoryManagerMXBeans) {
if (memoryManagerMXBean.isValid()) {
final String name = memoryManagerMXBean.isValid()
? memoryManagerMXBean.getName()
: memoryManagerMXBean.getName() + "(Invalid)";
table.row(name, toCol(memoryManagerMXBean.getMemoryPoolNames()));
jvmModel.addItem(group, name, memoryManagerMXBean.getMemoryPoolNames());
}
}
return table;
}
private Element drawMemoryTable(TableElement table) {
private void addMemory(JvmModel jvmModel) {
String group = "MEMORY";
MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
table.row("HEAP-MEMORY-USAGE\n[committed/init/max/used]",
formatMemoryByte(heapMemoryUsage.getCommitted())
+ "/" + formatMemoryByte(heapMemoryUsage.getInit())
+ "/" + formatMemoryByte(heapMemoryUsage.getMax())
+ "/" + formatMemoryByte(heapMemoryUsage.getUsed())
);
Map<String, Object> heapMemoryInfo = getMemoryUsageInfo("heap", heapMemoryUsage);
jvmModel.addItem(group, "HEAP-MEMORY-USAGE", heapMemoryInfo, "memory in bytes");
MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
table.row("NO-HEAP-MEMORY-USAGE\n[committed/init/max/used]",
formatMemoryByte(nonHeapMemoryUsage.getCommitted())
+ "/" + formatMemoryByte(nonHeapMemoryUsage.getInit())
+ "/" + formatMemoryByte(nonHeapMemoryUsage.getMax())
+ "/" + formatMemoryByte(nonHeapMemoryUsage.getUsed())
);
table.row("PENDING-FINALIZE-COUNT", "" + memoryMXBean.getObjectPendingFinalizationCount());
return table;
Map<String, Object> nonheapMemoryInfo = getMemoryUsageInfo("nonheap", nonHeapMemoryUsage);
jvmModel.addItem(group,"NO-HEAP-MEMORY-USAGE", nonheapMemoryInfo, "memory in bytes");
jvmModel.addItem(group,"PENDING-FINALIZE-COUNT", memoryMXBean.getObjectPendingFinalizationCount());
}
private String formatMemoryByte(long bytes){
return String.format("%s(%s)",bytes, StringUtils.humanReadableByteCount(bytes));
private Map<String, Object> getMemoryUsageInfo(String name, MemoryUsage heapMemoryUsage) {
Map<String, Object> memoryInfo = new LinkedHashMap<String, Object>();
memoryInfo.put("name", name);
memoryInfo.put("init", heapMemoryUsage.getInit());
memoryInfo.put("used", heapMemoryUsage.getUsed());
memoryInfo.put("committed", heapMemoryUsage.getCommitted());
memoryInfo.put("max", heapMemoryUsage.getMax());
return memoryInfo;
}
private Element drawOperatingSystemMXBeanTable(TableElement table) {
table.row("OS", operatingSystemMXBean.getName()).row("ARCH", operatingSystemMXBean.getArch())
.row("PROCESSORS-COUNT", "" + operatingSystemMXBean.getAvailableProcessors())
.row("LOAD-AVERAGE", "" + operatingSystemMXBean.getSystemLoadAverage())
.row("VERSION", operatingSystemMXBean.getVersion());
return table;
private void addOperatingSystem(JvmModel jvmModel) {
String group = "OPERATING-SYSTEM";
jvmModel.addItem(group,"OS", operatingSystemMXBean.getName())
.addItem(group,"ARCH", operatingSystemMXBean.getArch())
.addItem(group,"PROCESSORS-COUNT", operatingSystemMXBean.getAvailableProcessors())
.addItem(group,"LOAD-AVERAGE", operatingSystemMXBean.getSystemLoadAverage())
.addItem(group,"VERSION", operatingSystemMXBean.getVersion());
}
private Element drawThreadTable(TableElement table) {
table.row("COUNT", "" + threadMXBean.getThreadCount())
.row("DAEMON-COUNT", "" + threadMXBean.getDaemonThreadCount())
.row("PEAK-COUNT", "" + threadMXBean.getPeakThreadCount())
.row("STARTED-COUNT", "" + threadMXBean.getTotalStartedThreadCount())
.row("DEADLOCK-COUNT","" + getDeadlockedThreadsCount(threadMXBean));
return table;
private void addThread(JvmModel jvmModel) {
String group = "THREAD";
jvmModel.addItem(group, "COUNT", threadMXBean.getThreadCount())
.addItem(group, "DAEMON-COUNT", threadMXBean.getDaemonThreadCount())
.addItem(group, "PEAK-COUNT", threadMXBean.getPeakThreadCount())
.addItem(group, "STARTED-COUNT", threadMXBean.getTotalStartedThreadCount())
.addItem(group, "DEADLOCK-COUNT",getDeadlockedThreadsCount(threadMXBean));
}
private int getDeadlockedThreadsCount(ThreadMXBean threads) {
final long[] ids = threads.findDeadlockedThreads();
if (ids == null) {

@ -0,0 +1,120 @@
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.model.JvmModel;
import com.taobao.arthas.core.command.model.JvmItemVO;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static com.taobao.text.ui.Element.label;
/**
* View of 'jvm' command
*
* @author gongdewei 2020/4/24
*/
public class JvmView extends ResultView<JvmModel> {
@Override
public void draw(CommandProcess process, JvmModel result) {
TableElement table = new TableElement(2, 5).leftCellPadding(1).rightCellPadding(1);
for (Map.Entry<String, List<JvmItemVO>> entry : result.getJvmInfo().entrySet()) {
String group = entry.getKey();
List<JvmItemVO> items = entry.getValue();
table.row(true, label(group).style(Decoration.bold.bold()));
for (JvmItemVO item : items) {
String valueStr;
if (item.getValue() instanceof Map && item.getName().endsWith("MEMORY-USAGE")) {
valueStr = renderMemoryUsage((Map<String, Object>) item.getValue());
} else {
valueStr = renderItemValue(item.getValue());
}
if (item.getDesc() != null) {
table.row(item.getName() + "\n[" + item.getDesc() + "]", valueStr);
} else {
table.row(item.getName(), valueStr);
}
}
table.row("", "");
}
process.write(RenderUtil.render(table, process.width()));
}
private String renderCountTime(long[] value) {
//count/time
return value[0] + "/" + value[1];
}
private String renderItemValue(Object value) {
if (value == null) {
return "null";
}
if (value instanceof Collection) {
return renderCollectionValue((Collection) value);
} else if (value instanceof String[]) {
return renderArrayValue((String[]) value);
} else if (value instanceof Map) {
return renderMapValue((Map) value);
}
return String.valueOf(value);
}
private String renderCollectionValue(Collection<String> strings) {
final StringBuilder colSB = new StringBuilder();
if (strings.isEmpty()) {
colSB.append("[]");
} else {
for (String str : strings) {
colSB.append(str).append("\n");
}
}
return colSB.toString();
}
private String renderArrayValue(String... stringArray) {
final StringBuilder colSB = new StringBuilder();
if (null == stringArray
|| stringArray.length == 0) {
colSB.append("[]");
} else {
for (String str : stringArray) {
colSB.append(str).append("\n");
}
}
return colSB.toString();
}
private String renderMapValue(Map<String, Object> valueMap) {
final StringBuilder colSB = new StringBuilder();
if (valueMap != null) {
for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
colSB.append(entry.getKey()).append(" : ").append(entry.getValue()).append("\n");
}
}
return colSB.toString();
}
private String renderMemoryUsage(Map<String, Object> valueMap) {
final StringBuilder colSB = new StringBuilder();
String[] keys = new String[]{"init", "used", "committed", "max"};
for (String key : keys) {
Object value = valueMap.get(key);
String valueStr = value != null ? formatMemoryByte((Long) value) : "";
colSB.append(key).append(" : ").append(valueStr).append("\n");
}
return colSB.toString();
}
private String formatMemoryByte(long bytes) {
return String.format("%s(%s)", bytes, StringUtils.humanReadableByteCount(bytes));
}
}
Loading…
Cancel
Save