1 /* 2 * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.jconsole; 27 28 import java.awt.*; 29 import java.io.*; 30 import java.lang.management.*; 31 import java.lang.reflect.*; 32 import java.text.*; 33 import java.util.*; 34 import java.util.concurrent.*; 35 36 import javax.swing.*; 37 38 39 import static sun.tools.jconsole.Formatter.*; 40 import static sun.tools.jconsole.Utilities.*; 41 42 @SuppressWarnings("serial") 43 class SummaryTab extends Tab { 44 private static final String cpuUsageKey = "cpu"; 45 46 private static final String newDivider = "<tr><td colspan=4><font size =-1><hr>"; 47 private static final String newTable = "<tr><td colspan=4 align=left><table cellpadding=1>"; 48 private static final String newLeftTable = "<tr><td colspan=2 align=left><table cellpadding=1>"; 49 private static final String newRightTable = "<td colspan=2 align=left><table cellpadding=1>"; 50 private static final String endTable = "</table>"; 51 52 private static final int CPU_DECIMALS = 1; 53 54 private CPUOverviewPanel overviewPanel; 55 private DateFormat headerDateTimeFormat; 56 private String pathSeparator = null; 57 HTMLPane info; 58 59 private static class Result { 60 long upTime = -1L; 61 long processCpuTime = -1L; 62 long timeStamp; 63 int nCPUs; 64 String summary; 65 } 66 67 public static String getTabName() { 68 return Messages.SUMMARY_TAB_TAB_NAME; 69 } 70 71 public SummaryTab(VMPanel vmPanel) { 72 super(vmPanel, getTabName()); 73 74 setLayout(new BorderLayout()); 75 76 info = new HTMLPane(); 77 setAccessibleName(info, getTabName()); 78 add(new JScrollPane(info)); 79 80 headerDateTimeFormat = 81 Formatter.getDateTimeFormat(Messages.SUMMARY_TAB_HEADER_DATE_TIME_FORMAT); 82 } 83 84 public SwingWorker<?, ?> newSwingWorker() { 85 return new SwingWorker<Result, Object>() { 86 public Result doInBackground() { 87 return formatSummary(); 88 } 89 90 91 protected void done() { 92 try { 93 Result result = get(); 94 if (result != null) { 95 info.setText(result.summary); 96 if (overviewPanel != null && 97 result.upTime > 0L && 98 result.processCpuTime >= 0L) { 99 100 overviewPanel.updateCPUInfo(result); 101 } 102 } 103 } catch (InterruptedException ex) { 104 } catch (ExecutionException ex) { 105 if (JConsole.isDebug()) { 106 ex.printStackTrace(); 107 } 108 } 109 } 110 }; 111 } 112 113 StringBuilder buf; 114 115 synchronized Result formatSummary() { 116 Result result = new Result(); 117 ProxyClient proxyClient = vmPanel.getProxyClient(); 118 if (proxyClient.isDead()) { 119 return null; 120 } 121 122 buf = new StringBuilder(); 123 append("<table cellpadding=1>"); 124 125 try { 126 RuntimeMXBean rmBean = proxyClient.getRuntimeMXBean(); 127 CompilationMXBean cmpMBean = proxyClient.getCompilationMXBean(); 128 ThreadMXBean tmBean = proxyClient.getThreadMXBean(); 129 MemoryMXBean memoryBean = proxyClient.getMemoryMXBean(); 130 ClassLoadingMXBean clMBean = proxyClient.getClassLoadingMXBean(); 131 OperatingSystemMXBean osMBean = proxyClient.getOperatingSystemMXBean(); 132 com.sun.management.OperatingSystemMXBean sunOSMBean = 133 proxyClient.getSunOperatingSystemMXBean(); 134 135 append("<tr><td colspan=4>"); 136 append("<center><b>" + Messages.SUMMARY_TAB_TAB_NAME + "</b></center>"); 137 String dateTime = 138 headerDateTimeFormat.format(System.currentTimeMillis()); 139 append("<center>" + dateTime + "</center>"); 140 141 append(newDivider); 142 143 { // VM info 144 append(newLeftTable); 145 append(Messages.CONNECTION_NAME, vmPanel.getDisplayName()); 146 append(Messages.VIRTUAL_MACHINE, 147 Resources.format(Messages.SUMMARY_TAB_VM_VERSION, 148 rmBean.getVmName(), rmBean.getVmVersion())); 149 append(Messages.VENDOR, rmBean.getVmVendor()); 150 append(Messages.NAME, rmBean.getName()); 151 append(endTable); 152 153 append(newRightTable); 154 result.upTime = rmBean.getUptime(); 155 append(Messages.UPTIME, formatTime(result.upTime)); 156 if (sunOSMBean != null) { 157 result.processCpuTime = sunOSMBean.getProcessCpuTime(); 158 append(Messages.PROCESS_CPU_TIME, formatNanoTime(result.processCpuTime)); 159 } 160 161 if (cmpMBean != null) { 162 append(Messages.JIT_COMPILER, cmpMBean.getName()); 163 append(Messages.TOTAL_COMPILE_TIME, 164 cmpMBean.isCompilationTimeMonitoringSupported() 165 ? formatTime(cmpMBean.getTotalCompilationTime()) 166 : Messages.UNAVAILABLE); 167 } else { 168 append(Messages.JIT_COMPILER, Messages.UNAVAILABLE); 169 } 170 append(endTable); 171 } 172 173 append(newDivider); 174 175 { // Threads and Classes 176 append(newLeftTable); 177 int tlCount = tmBean.getThreadCount(); 178 int tdCount = tmBean.getDaemonThreadCount(); 179 int tpCount = tmBean.getPeakThreadCount(); 180 long ttCount = tmBean.getTotalStartedThreadCount(); 181 String[] strings1 = formatLongs(tlCount, tpCount, 182 tdCount, ttCount); 183 append(Messages.LIVE_THREADS, strings1[0]); 184 append(Messages.PEAK, strings1[1]); 185 append(Messages.DAEMON_THREADS, strings1[2]); 186 append(Messages.TOTAL_THREADS_STARTED, strings1[3]); 187 append(endTable); 188 189 append(newRightTable); 190 long clCount = clMBean.getLoadedClassCount(); 191 long cuCount = clMBean.getUnloadedClassCount(); 192 long ctCount = clMBean.getTotalLoadedClassCount(); 193 String[] strings2 = formatLongs(clCount, cuCount, ctCount); 194 append(Messages.CURRENT_CLASSES_LOADED, strings2[0]); 195 append(Messages.TOTAL_CLASSES_LOADED, strings2[2]); 196 append(Messages.TOTAL_CLASSES_UNLOADED, strings2[1]); 197 append(null, ""); 198 append(endTable); 199 } 200 201 append(newDivider); 202 203 { // Memory 204 MemoryUsage u = memoryBean.getHeapMemoryUsage(); 205 206 append(newLeftTable); 207 String[] strings1 = formatKByteStrings(u.getUsed(), u.getMax()); 208 append(Messages.CURRENT_HEAP_SIZE, strings1[0]); 209 append(Messages.MAXIMUM_HEAP_SIZE, strings1[1]); 210 append(endTable); 211 212 append(newRightTable); 213 String[] strings2 = formatKByteStrings(u.getCommitted()); 214 append(Messages.COMMITTED_MEMORY, strings2[0]); 215 append(Messages.SUMMARY_TAB_PENDING_FINALIZATION_LABEL, 216 Resources.format(Messages.SUMMARY_TAB_PENDING_FINALIZATION_VALUE, 217 memoryBean.getObjectPendingFinalizationCount())); 218 append(endTable); 219 220 append(newTable); 221 Collection<GarbageCollectorMXBean> garbageCollectors = 222 proxyClient.getGarbageCollectorMXBeans(); 223 for (GarbageCollectorMXBean garbageCollectorMBean : garbageCollectors) { 224 String gcName = garbageCollectorMBean.getName(); 225 long gcCount = garbageCollectorMBean.getCollectionCount(); 226 long gcTime = garbageCollectorMBean.getCollectionTime(); 227 228 append(Messages.GARBAGE_COLLECTOR, 229 Resources.format(Messages.GC_INFO, gcName, gcCount, 230 (gcTime >= 0) ? formatTime(gcTime) 231 : Messages.UNAVAILABLE), 232 4); 233 } 234 append(endTable); 235 } 236 237 append(newDivider); 238 239 { // Operating System info 240 append(newLeftTable); 241 String osName = osMBean.getName(); 242 String osVersion = osMBean.getVersion(); 243 String osArch = osMBean.getArch(); 244 result.nCPUs = osMBean.getAvailableProcessors(); 245 append(Messages.OPERATING_SYSTEM, osName + " " + osVersion); 246 append(Messages.ARCHITECTURE, osArch); 247 append(Messages.NUMBER_OF_PROCESSORS, result.nCPUs+""); 248 249 if (pathSeparator == null) { 250 // Must use separator of remote OS, not File.pathSeparator 251 // from this local VM. In the future, consider using 252 // RuntimeMXBean to get the remote system property. 253 pathSeparator = osName.startsWith("Windows ") ? ";" : ":"; 254 } 255 256 if (sunOSMBean != null) { 257 String[] kbStrings1 = 258 formatKByteStrings(sunOSMBean.getCommittedVirtualMemorySize()); 259 260 String[] kbStrings2 = 261 formatKByteStrings(sunOSMBean.getTotalPhysicalMemorySize(), 262 sunOSMBean.getFreePhysicalMemorySize(), 263 sunOSMBean.getTotalSwapSpaceSize(), 264 sunOSMBean.getFreeSwapSpaceSize()); 265 266 append(Messages.COMMITTED_VIRTUAL_MEMORY, kbStrings1[0]); 267 append(endTable); 268 269 append(newRightTable); 270 append(Messages.TOTAL_PHYSICAL_MEMORY, kbStrings2[0]); 271 append(Messages.FREE_PHYSICAL_MEMORY, kbStrings2[1]); 272 append(Messages.TOTAL_SWAP_SPACE, kbStrings2[2]); 273 append(Messages.FREE_SWAP_SPACE, kbStrings2[3]); 274 } 275 276 append(endTable); 277 } 278 279 append(newDivider); 280 281 { // VM arguments and paths 282 append(newTable); 283 String args = ""; 284 java.util.List<String> inputArguments = rmBean.getInputArguments(); 285 for (String arg : inputArguments) { 286 args += arg + " "; 287 } 288 append(Messages.VM_ARGUMENTS, args, 4); 289 append(Messages.CLASS_PATH, rmBean.getClassPath(), 4); 290 append(Messages.LIBRARY_PATH, rmBean.getLibraryPath(), 4); 291 append(Messages.BOOT_CLASS_PATH, 292 rmBean.isBootClassPathSupported() 293 ? rmBean.getBootClassPath() 294 : Messages.UNAVAILABLE, 295 4); 296 append(endTable); 297 } 298 } catch (IOException e) { 299 if (JConsole.isDebug()) { 300 e.printStackTrace(); 301 } 302 proxyClient.markAsDead(); 303 return null; 304 } catch (UndeclaredThrowableException e) { 305 if (JConsole.isDebug()) { 306 e.printStackTrace(); 307 } 308 proxyClient.markAsDead(); 309 return null; 310 } 311 312 append("</table>"); 313 314 result.timeStamp = System.currentTimeMillis(); 315 result.summary = buf.toString(); 316 317 return result; 318 } 319 320 private synchronized void append(String str) { 321 buf.append(str); 322 } 323 324 void append(String label, String value) { 325 append(newRow(label, value)); 326 } 327 328 private void append(String label, String value, int columnPerRow) { 329 if (columnPerRow == 4 && pathSeparator != null) { 330 value = value.replace(pathSeparator, 331 "<b></b>" + pathSeparator); 332 } 333 append(newRow(label, value, columnPerRow)); 334 } 335 336 OverviewPanel[] getOverviewPanels() { 337 if (overviewPanel == null) { 338 overviewPanel = new CPUOverviewPanel(); 339 } 340 return new OverviewPanel[] { overviewPanel }; 341 } 342 343 private static class CPUOverviewPanel extends OverviewPanel { 344 private long prevUpTime, prevProcessCpuTime; 345 346 CPUOverviewPanel() { 347 super(Messages.CPU_USAGE, cpuUsageKey, Messages.CPU_USAGE, Plotter.Unit.PERCENT); 348 getPlotter().setDecimals(CPU_DECIMALS); 349 } 350 351 public void updateCPUInfo(Result result) { 352 if (prevUpTime > 0L && result.upTime > prevUpTime) { 353 // elapsedCpu is in ns and elapsedTime is in ms. 354 long elapsedCpu = result.processCpuTime - prevProcessCpuTime; 355 long elapsedTime = result.upTime - prevUpTime; 356 // cpuUsage could go higher than 100% because elapsedTime 357 // and elapsedCpu are not fetched simultaneously. Limit to 358 // 99% to avoid Plotter showing a scale from 0% to 200%. 359 float cpuUsage = 360 Math.min(99F, 361 elapsedCpu / (elapsedTime * 10000F * result.nCPUs)); 362 363 getPlotter().addValues(result.timeStamp, 364 Math.round(cpuUsage * Math.pow(10.0, CPU_DECIMALS))); 365 getInfoLabel().setText(Resources.format(Messages.CPU_USAGE_FORMAT, 366 String.format("%."+CPU_DECIMALS+"f", cpuUsage))); 367 } 368 this.prevUpTime = result.upTime; 369 this.prevProcessCpuTime = result.processCpuTime; 370 } 371 } 372 }