package games.strategy.debug; import java.awt.Frame; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; import games.strategy.engine.ClientContext; import games.strategy.engine.framework.GameRunner; import games.strategy.engine.framework.system.Memory; /** * Moved out of Console class, so that we don't need swing. */ public class DebugUtils { private static final ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); public static String getThreadDumps() { final StringBuilder result = new StringBuilder(); result.append("THREAD DUMP\n"); final ThreadInfo[] threadInfo = threadMxBean.getThreadInfo(threadMxBean.getAllThreadIds(), Integer.MAX_VALUE); for (final ThreadInfo info : threadInfo) { if (info != null) { result.append("thread<").append(info.getThreadId()).append(",").append(info.getThreadName()).append(">\n") .append("state:") .append(info.getThreadState()).append("\n"); if (info.getLockName() != null) { result.append("locked on:").append(info.getLockName()).append(" locked owned by:<") .append(info.getLockOwnerId()) .append(",").append(info.getLockOwnerName()).append(">\n"); } final StackTraceElement[] stackTrace = info.getStackTrace(); for (final StackTraceElement element : stackTrace) { result.append(" "); result.append(element); result.append("\n"); } result.append("\n"); } } long[] deadlocks = threadMxBean.findDeadlockedThreads(); if (deadlocks != null) { result.append("DEADLOCKS!!"); for (final long l : deadlocks) { result.append(l).append("\n"); } } return result.toString(); } public static String getMemory() { System.gc(); System.runFinalization(); System.gc(); final int mb = 1024 * 1024; final StringBuilder buf = new StringBuilder("Heap utilization statistics [MB]\r\n"); final Runtime runtime = Runtime.getRuntime(); buf.append("Used Memory: ").append((runtime.totalMemory() - runtime.freeMemory()) / mb).append("\r\n"); buf.append("Free memory: ").append(runtime.freeMemory() / mb).append("\r\n"); buf.append("Total memory: ").append(runtime.totalMemory() / mb).append("\r\n"); buf.append("Max memory: ").append(runtime.maxMemory() / mb).append("\r\n"); final int currentMaxSetting = Memory.getMaxMemoryFromSystemIniFileInMB(GameRunner.getSystemIni()); if (currentMaxSetting > 0) { buf.append("Max Memory user setting within 22% of: ").append(currentMaxSetting).append("\r\n"); } return buf.toString(); } public static String getProperties() { final StringBuilder buf = new StringBuilder("SYSTEM PROPERTIES\n"); final Properties props = System.getProperties(); final List<String> keys = new ArrayList<>(props.stringPropertyNames()); Collections.sort(keys); for (final String property : keys) { final String value = props.getProperty(property); buf.append(property).append(" ").append(value).append("\n"); } return buf.toString(); } public static String getDebugReportHeadless() { final StringBuilder result = new StringBuilder(500); result.append(getThreadDumps()); result.append(getProperties()); result.append(getMemory()); result.append("ENGINE VERSION: ").append(ClientContext.engineVersion()).append("\n"); return result.toString(); } public static String getDebugReportWithFramesAndWindows() { final StringBuilder result = new StringBuilder(500); result.append("CONSOLE_OUTPUT:\n"); result.append(ErrorConsole.getConsole().getText()); result.append("\n"); result.append(getThreadDumps()); result.append(getProperties()); result.append(getMemory()); result.append(getOpenAppWindows()); result.append("ENGINE VERSION: ").append(ClientContext.engineVersion().getVersion()).append("\n"); return result.toString(); } private static String getOpenAppWindows() { final StringBuilder builder = new StringBuilder("WINDOWS\n"); for (final Frame f : Frame.getFrames()) { if (f.isVisible()) { builder.append("window:").append("class ").append(f.getClass()).append(" size ").append(f.getSize()) .append(" title ") .append(f.getTitle()).append("\n"); } } return builder.toString(); } }