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.net.URL; 33 import java.text.*; 34 import java.util.*; 35 import java.util.concurrent.*; 36 37 import javax.swing.*; 38 import javax.swing.event.*; 39 import javax.swing.text.*; 40 41 import static sun.tools.jconsole.Formatter.*; 42 import static sun.tools.jconsole.Resources.*; 43 import static sun.tools.jconsole.Utilities.*; 44 45 @SuppressWarnings("serial") 46 class SummaryTab extends Tab { 47 private static final String cpuUsageKey = "cpu"; 48 private static final String cpuUsageName = getText("CPU Usage"); 49 private static final String cpuUsageFormat = "CPUUsageFormat"; 50 51 private static final String newDivider = "<tr><td colspan=4><font size =-1><hr>"; 52 private static final String newTable = "<tr><td colspan=4 align=left><table cellpadding=1>"; 53 private static final String newLeftTable = "<tr><td colspan=2 align=left><table cellpadding=1>"; 54 private static final String newRightTable = "<td colspan=2 align=left><table cellpadding=1>"; 55 private static final String endTable = "</table>"; 56 57 private static final int CPU_DECIMALS = 1; 58 59 private CPUOverviewPanel overviewPanel; 60 private DateFormat headerDateTimeFormat; 61 private String pathSeparator = null; 62 HTMLPane info; 63 64 private static class Result { 65 long upTime = -1L; 66 long processCpuTime = -1L; 67 long timeStamp; 68 int nCPUs; 69 String summary; 70 } 71 72 public static String getTabName() { 73 return Resources.getText("SummaryTab.tabName"); 74 } 75 76 public SummaryTab(VMPanel vmPanel) { 77 super(vmPanel, getTabName()); 78 79 setLayout(new BorderLayout()); 80 81 info = new HTMLPane(); 82 setAccessibleName(info, getTabName()); 83 add(new JScrollPane(info)); 84 85 headerDateTimeFormat = 86 getDateTimeFormat("SummaryTab.headerDateTimeFormat"); 87 } 88 89 public SwingWorker<?, ?> newSwingWorker() { 90 return new SwingWorker<Result, Object>() { 91 public Result doInBackground() { 92 return formatSummary(); 93 } 94 95 96 protected void done() { 97 try { 98 Result result = get(); 99 if (result != null) { 100 info.setText(result.summary); 101 if (overviewPanel != null && 102 result.upTime > 0L && 103 result.processCpuTime >= 0L) { 104 105 overviewPanel.updateCPUInfo(result); 106 } 107 } 108 } catch (InterruptedException ex) { 109 } catch (ExecutionException ex) { 110 if (JConsole.isDebug()) { 111 ex.printStackTrace(); 112 } 113 } 114 } 115 }; 116 } 117 118 StringBuilder buf; 119 120 synchronized Result formatSummary() { 121 Result result = new Result(); 122 ProxyClient proxyClient = vmPanel.getProxyClient(); 123 if (proxyClient.isDead()) { 124 return null; 125 } 126 127 buf = new StringBuilder(); 128 append("<table cellpadding=1>"); 129 130 try { 131 RuntimeMXBean rmBean = proxyClient.getRuntimeMXBean(); 132 CompilationMXBean cmpMBean = proxyClient.getCompilationMXBean(); 133 ThreadMXBean tmBean = proxyClient.getThreadMXBean(); 134 MemoryMXBean memoryBean = proxyClient.getMemoryMXBean(); 135 ClassLoadingMXBean clMBean = proxyClient.getClassLoadingMXBean(); 136 OperatingSystemMXBean osMBean = proxyClient.getOperatingSystemMXBean(); 137 com.sun.management.OperatingSystemMXBean sunOSMBean = 138 proxyClient.getSunOperatingSystemMXBean(); 139 140 append("<tr><td colspan=4>"); 141 append("<center><b>" + getText("SummaryTab.tabName") + "</b></center>"); 142 String dateTime = 143 headerDateTimeFormat.format(System.currentTimeMillis()); 144 append("<center>" + dateTime + "</center>"); 145 146 append(newDivider); 147 148 { // VM info 149 append(newLeftTable); 150 append("Connection name", vmPanel.getDisplayName()); 151 append("Virtual Machine", 152 getText("SummaryTab.vmVersion", 153 rmBean.getVmName(), rmBean.getVmVersion())); 154 append("Vendor", rmBean.getVmVendor()); 155 append("Name", rmBean.getName()); 156 append(endTable); 157 158 append(newRightTable); 159 result.upTime = rmBean.getUptime(); 160 append("Uptime", formatTime(result.upTime)); 161 if (sunOSMBean != null) { 162 result.processCpuTime = sunOSMBean.getProcessCpuTime(); 163 append("Process CPU time", formatNanoTime(result.processCpuTime)); 164 } 165 166 if (cmpMBean != null) { 167 append("JIT compiler", cmpMBean.getName()); 168 append("Total compile time", 169 cmpMBean.isCompilationTimeMonitoringSupported() 170 ? formatTime(cmpMBean.getTotalCompilationTime()) 171 : getText("Unavailable")); 172 } else { 173 append("JIT compiler", getText("Unavailable")); 174 } 175 append(endTable); 176 } 177 178 append(newDivider); 179 180 { // Threads and Classes 181 append(newLeftTable); 182 int tlCount = tmBean.getThreadCount(); 183 int tdCount = tmBean.getDaemonThreadCount(); 184 int tpCount = tmBean.getPeakThreadCount(); 185 long ttCount = tmBean.getTotalStartedThreadCount(); 186 String[] strings1 = formatLongs(tlCount, tpCount, 187 tdCount, ttCount); 188 append("Live Threads", strings1[0]); 189 append("Peak", strings1[1]); 190 append("Daemon threads", strings1[2]); 191 append("Total threads started", strings1[3]); 192 append(endTable); 193 194 append(newRightTable); 195 long clCount = clMBean.getLoadedClassCount(); 196 long cuCount = clMBean.getUnloadedClassCount(); 197 long ctCount = clMBean.getTotalLoadedClassCount(); 198 String[] strings2 = formatLongs(clCount, cuCount, ctCount); 199 append("Current classes loaded", strings2[0]); 200 append("Total classes loaded", strings2[2]); 201 append("Total classes unloaded", strings2[1]); 202 append(null, ""); 203 append(endTable); 204 } 205 206 append(newDivider); 207 208 { // Memory 209 MemoryUsage u = memoryBean.getHeapMemoryUsage(); 210 211 append(newLeftTable); 212 String[] strings1 = formatKByteStrings(u.getUsed(), u.getMax()); 213 append("Current heap size", strings1[0]); 214 append("Maximum heap size", strings1[1]); 215 append(endTable); 216 217 append(newRightTable); 218 String[] strings2 = formatKByteStrings(u.getCommitted()); 219 append("Committed memory", strings2[0]); 220 append("SummaryTab.pendingFinalization.label", 221 getText("SummaryTab.pendingFinalization.value", 222 memoryBean.getObjectPendingFinalizationCount())); 223 append(endTable); 224 225 append(newTable); 226 Collection<GarbageCollectorMXBean> garbageCollectors = 227 proxyClient.getGarbageCollectorMXBeans(); 228 for (GarbageCollectorMXBean garbageCollectorMBean : garbageCollectors) { 229 String gcName = garbageCollectorMBean.getName(); 230 long gcCount = garbageCollectorMBean.getCollectionCount(); 231 long gcTime = garbageCollectorMBean.getCollectionTime(); 232 233 append("Garbage collector", 234 getText("GcInfo", gcName, gcCount, 235 (gcTime >= 0) ? formatTime(gcTime) 236 : getText("Unavailable")), 237 4); 238 } 239 append(endTable); 240 } 241 242 append(newDivider); 243 244 { // Operating System info 245 append(newLeftTable); 246 String osName = osMBean.getName(); 247 String osVersion = osMBean.getVersion(); 248 String osArch = osMBean.getArch(); 249 result.nCPUs = osMBean.getAvailableProcessors(); 250 append("Operating System", osName + " " + osVersion); 251 append("Architecture", osArch); 252 append("Number of processors", result.nCPUs+""); 253 254 if (pathSeparator == null) { 255 // Must use separator of remote OS, not File.pathSeparator 256 // from this local VM. In the future, consider using 257 // RuntimeMXBean to get the remote system property. 258 pathSeparator = osName.startsWith("Windows ") ? ";" : ":"; 259 } 260 261 if (sunOSMBean != null) { 262 String[] kbStrings1 = 263 formatKByteStrings(sunOSMBean.getCommittedVirtualMemorySize()); 264 265 String[] kbStrings2 = 266 formatKByteStrings(sunOSMBean.getTotalPhysicalMemorySize(), 267 sunOSMBean.getFreePhysicalMemorySize(), 268 sunOSMBean.getTotalSwapSpaceSize(), 269 sunOSMBean.getFreeSwapSpaceSize()); 270 271 append("Committed virtual memory", kbStrings1[0]); 272 append(endTable); 273 274 append(newRightTable); 275 append("Total physical memory", kbStrings2[0]); 276 append("Free physical memory", kbStrings2[1]); 277 append("Total swap space", kbStrings2[2]); 278 append("Free swap space", kbStrings2[3]); 279 } 280 281 append(endTable); 282 } 283 284 append(newDivider); 285 286 { // VM arguments and paths 287 append(newTable); 288 String args = ""; 289 java.util.List<String> inputArguments = rmBean.getInputArguments(); 290 for (String arg : inputArguments) { 291 args += arg + " "; 292 } 293 append("VM arguments", args, 4); 294 append("Class path", rmBean.getClassPath(), 4); 295 append("Library path", rmBean.getLibraryPath(), 4); 296 append("Boot class path", 297 rmBean.isBootClassPathSupported() 298 ? rmBean.getBootClassPath() 299 : getText("Unavailable"), 300 4); 301 append(endTable); 302 } 303 } catch (IOException e) { 304 if (JConsole.isDebug()) { 305 e.printStackTrace(); 306 } 307 proxyClient.markAsDead(); 308 return null; 309 } catch (UndeclaredThrowableException e) { 310 if (JConsole.isDebug()) { 311 e.printStackTrace(); 312 } 313 proxyClient.markAsDead(); 314 return null; 315 } 316 317 append("</table>"); 318 319 result.timeStamp = System.currentTimeMillis(); 320 result.summary = buf.toString(); 321 322 return result; 323 } 324 325 private synchronized void append(String str) { 326 buf.append(str); 327 } 328 329 void append(String label, String value) { 330 append(newRow((label != null) ? getText(label) : label, value)); 331 } 332 333 private void append(String label, String value, int columnPerRow) { 334 if (columnPerRow == 4 && pathSeparator != null) { 335 value = value.replace(pathSeparator, 336 "<b></b>" + pathSeparator); 337 } 338 append(newRow(getText(label), value, columnPerRow)); 339 } 340 341 void append(String label1, String value1, 342 String label2, String value2) { 343 append(newRow(getText(label1), value1, 344 getText(label2), value2)); 345 } 346 347 OverviewPanel[] getOverviewPanels() { 348 if (overviewPanel == null) { 349 overviewPanel = new CPUOverviewPanel(); 350 } 351 return new OverviewPanel[] { overviewPanel }; 352 } 353 354 private static class CPUOverviewPanel extends OverviewPanel { 355 private long prevUpTime, prevProcessCpuTime; 356 357 CPUOverviewPanel() { 358 super(getText("CPU Usage"), cpuUsageKey, cpuUsageName, Plotter.Unit.PERCENT); 359 getPlotter().setDecimals(CPU_DECIMALS); 360 } 361 362 public void updateCPUInfo(Result result) { 363 if (prevUpTime > 0L && result.upTime > prevUpTime) { 364 // elapsedCpu is in ns and elapsedTime is in ms. 365 long elapsedCpu = result.processCpuTime - prevProcessCpuTime; 366 long elapsedTime = result.upTime - prevUpTime; 367 // cpuUsage could go higher than 100% because elapsedTime 368 // and elapsedCpu are not fetched simultaneously. Limit to 369 // 99% to avoid Plotter showing a scale from 0% to 200%. 370 float cpuUsage = 371 Math.min(99F, 372 elapsedCpu / (elapsedTime * 10000F * result.nCPUs)); 373 374 getPlotter().addValues(result.timeStamp, 375 Math.round(cpuUsage * Math.pow(10.0, CPU_DECIMALS))); 376 getInfoLabel().setText(getText(cpuUsageFormat, 377 String.format("%."+CPU_DECIMALS+"f", cpuUsage))); 378 } 379 this.prevUpTime = result.upTime; 380 this.prevProcessCpuTime = result.processCpuTime; 381 } 382 } 383 384 385 386 }