J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2004-2007 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any 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 | } |