Showing the changes to java/pkg/sun/tools/jconsole/MemoryTab.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,780 @@ | |||
| 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.awt.event.*; | ||
| 30 | import java.io.*; | ||
| 31 | import java.lang.management.*; | ||
| 32 | import java.lang.reflect.*; | ||
| 33 | import java.util.*; | ||
| 34 | import java.util.concurrent.*; | ||
| 35 | |||
| 36 | import javax.accessibility.*; | ||
| 37 | import javax.management.*; | ||
| 38 | import javax.management.openmbean.CompositeData; | ||
| 39 | import javax.swing.*; | ||
| 40 | import javax.swing.border.*; | ||
| 41 | import javax.swing.text.*; | ||
| 42 | |||
| 43 | import sun.management.*; | ||
| 44 | |||
| 45 | import static sun.tools.jconsole.Formatter.*; | ||
| 46 | import static sun.tools.jconsole.OverviewPanel.*; | ||
| 47 | import static sun.tools.jconsole.Resources.*; | ||
| 48 | import static sun.tools.jconsole.Utilities.*; | ||
| 49 | |||
| 50 | @SuppressWarnings("serial") | ||
| 51 | class MemoryTab extends Tab implements ActionListener, ItemListener { | ||
| 52 | JComboBox plotterChoice; | ||
| 53 | TimeComboBox timeComboBox; | ||
| 54 | JButton gcButton; | ||
| 55 | |||
| 56 | PlotterPanel plotterPanel; | ||
| 57 | JPanel bottomPanel; | ||
| 58 | HTMLPane details; | ||
| 59 | PoolChart poolChart; | ||
| 60 | |||
| 61 | ArrayList<Plotter> plotterList; | ||
| 62 | Plotter heapPlotter, nonHeapPlotter; | ||
| 63 | |||
| 64 | private MemoryOverviewPanel overviewPanel; | ||
| 65 | |||
| 66 | private static final String usedKey = "used"; | ||
| 67 | private static final String committedKey = "committed"; | ||
| 68 | private static final String maxKey = "max"; | ||
| 69 | private static final String thresholdKey = "threshold"; | ||
| 70 | |||
| 71 | private static final String usedName = Resources.getText("Used"); | ||
| 72 | private static final String committedName = Resources.getText("Committed"); | ||
| 73 | private static final String maxName = Resources.getText("Max"); | ||
| 74 | private static final String thresholdName = Resources.getText("Threshold"); | ||
| 75 | |||
| 76 | private static final Color usedColor = Plotter.defaultColor; | ||
| 77 | private static final Color committedColor = null; | ||
| 78 | private static final Color maxColor = null; | ||
| 79 | private static final Color thresholdColor = Color.red; | ||
| 80 | |||
| 81 | private static final String infoLabelFormat = "MemoryTab.infoLabelFormat"; | ||
| 82 | |||
| 83 | /* | ||
| 84 | Hierarchy of panels and layouts for this tab: | ||
| 85 | |||
| 86 | MemoryTab (BorderLayout) | ||
| 87 | |||
| 88 | North: topPanel (BorderLayout) | ||
| 89 | |||
| 90 | Center: controlPanel (FlowLayout) | ||
| 91 | plotterChoice, timeComboBox | ||
| 92 | |||
| 93 | East: topRightPanel (FlowLayout) | ||
| 94 | gcButton | ||
| 95 | |||
| 96 | Center: plotterPanel | ||
| 97 | |||
| 98 | Center: plotter | ||
| 99 | |||
| 100 | South: bottomPanel (BorderLayout) | ||
| 101 | |||
| 102 | Center: details | ||
| 103 | East: poolChart | ||
| 104 | */ | ||
| 105 | |||
| 106 | |||
| 107 | public static String getTabName() { | ||
| 108 | return getText("Memory"); | ||
| 109 | } | ||
| 110 | |||
| 111 | public MemoryTab(VMPanel vmPanel) { | ||
| 112 | super(vmPanel, getTabName()); | ||
| 113 | |||
| 114 | setLayout(new BorderLayout(0, 0)); | ||
| 115 | setBorder(new EmptyBorder(4, 4, 3, 4)); | ||
| 116 | |||
| 117 | JPanel topPanel = new JPanel(new BorderLayout()); | ||
| 118 | plotterPanel = new PlotterPanel(null); | ||
| 119 | bottomPanel = new JPanel(new BorderLayout()); | ||
| 120 | |||
| 121 | add(topPanel, BorderLayout.NORTH); | ||
| 122 | add(plotterPanel, BorderLayout.CENTER); | ||
| 123 | |||
| 124 | JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 20, 5)); | ||
| 125 | topPanel.add(controlPanel, BorderLayout.CENTER); | ||
| 126 | |||
| 127 | // Plotter choice | ||
| 128 | plotterChoice = new JComboBox(); | ||
| 129 | plotterChoice.addItemListener(this); | ||
| 130 | controlPanel.add(new LabeledComponent(getText("Chart:"), | ||
| 131 | getMnemonicInt("Chart:"), | ||
| 132 | plotterChoice)); | ||
| 133 | |||
| 134 | // Range control | ||
| 135 | timeComboBox = new TimeComboBox(); | ||
| 136 | controlPanel.add(new LabeledComponent(getText("Time Range:"), | ||
| 137 | getMnemonicInt("Time Range:"), | ||
| 138 | timeComboBox)); | ||
| 139 | |||
| 140 | gcButton = new JButton(getText("Perform GC")); | ||
| 141 | gcButton.setMnemonic(getMnemonicInt("Perform GC")); | ||
| 142 | gcButton.addActionListener(this); | ||
| 143 | gcButton.setToolTipText(getText("Perform GC.toolTip")); | ||
| 144 | JPanel topRightPanel = new JPanel(); | ||
| 145 | topRightPanel.setBorder(new EmptyBorder(0, 65-8, 0, 70)); | ||
| 146 | topRightPanel.add(gcButton); | ||
| 147 | topPanel.add(topRightPanel, BorderLayout.AFTER_LINE_ENDS); | ||
| 148 | |||
| 149 | bottomPanel.setBorder(new CompoundBorder(new TitledBorder(getText("Details")), | ||
| 150 | new EmptyBorder(10, 10, 10, 10))); | ||
| 151 | |||
| 152 | details = new HTMLPane(); | ||
| 153 | setAccessibleName(details, getText("Details")); | ||
| 154 | bottomPanel.add(new JScrollPane(details), BorderLayout.CENTER); | ||
| 155 | |||
| 156 | poolChart = new PoolChart(); | ||
| 157 | bottomPanel.add(poolChart, BorderLayout.AFTER_LINE_ENDS); | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | private void createPlotters() throws IOException { | ||
| 162 | plotterList = new ArrayList<Plotter>(); | ||
| 163 | |||
| 164 | ProxyClient proxyClient = vmPanel.getProxyClient(); | ||
| 165 | |||
| 166 | heapPlotter = new Plotter(Plotter.Unit.BYTES) { | ||
| 167 | public String toString() { | ||
| 168 | return Resources.getText("Heap Memory Usage"); | ||
| 169 | } | ||
| 170 | }; | ||
| 171 | proxyClient.addWeakPropertyChangeListener(heapPlotter); | ||
| 172 | |||
| 173 | nonHeapPlotter = new Plotter(Plotter.Unit.BYTES) { | ||
| 174 | public String toString() { | ||
| 175 | return Resources.getText("Non-Heap Memory Usage"); | ||
| 176 | } | ||
| 177 | }; | ||
| 178 | |||
| 179 | setAccessibleName(heapPlotter, | ||
| 180 | getText("MemoryTab.heapPlotter.accessibleName")); | ||
| 181 | setAccessibleName(nonHeapPlotter, | ||
| 182 | getText("MemoryTab.nonHeapPlotter.accessibleName")); | ||
| 183 | |||
| 184 | proxyClient.addWeakPropertyChangeListener(nonHeapPlotter); | ||
| 185 | |||
| 186 | heapPlotter.createSequence(usedKey, usedName, usedColor, true); | ||
| 187 | heapPlotter.createSequence(committedKey, committedName, committedColor, false); | ||
| 188 | heapPlotter.createSequence(maxKey, maxName, maxColor, false); | ||
| 189 | |||
| 190 | nonHeapPlotter.createSequence(usedKey, usedName, usedColor, true); | ||
| 191 | nonHeapPlotter.createSequence(committedKey, committedName, committedColor, false); | ||
| 192 | nonHeapPlotter.createSequence(maxKey, maxName, maxColor, false); | ||
| 193 | |||
| 194 | plotterList.add(heapPlotter); | ||
| 195 | plotterList.add(nonHeapPlotter); | ||
| 196 | |||
| 197 | // Now add memory pools | ||
| 198 | Map<ObjectName, MBeanInfo> mBeanMap = proxyClient.getMBeans("java.lang"); | ||
| 199 | Set<ObjectName> keys = mBeanMap.keySet(); | ||
| 200 | ObjectName[] objectNames = keys.toArray(new ObjectName[keys.size()]); | ||
| 201 | ArrayList<PoolPlotter> nonHeapPlotters = new ArrayList<PoolPlotter>(2); | ||
| 202 | for (ObjectName objectName : objectNames) { | ||
| 203 | String type = objectName.getKeyProperty("type"); | ||
| 204 | if (type.equals("MemoryPool")) { | ||
| 205 | String name = getText("MemoryPoolLabel", | ||
| 206 | objectName.getKeyProperty("name")); | ||
| 207 | // Heap or non-heap? | ||
| 208 | boolean isHeap = false; | ||
| 209 | AttributeList al = | ||
| 210 | proxyClient.getAttributes(objectName, | ||
| 211 | new String[] { "Type" }); | ||
| 212 | if (al.size() > 0) { | ||
| 213 | isHeap = MemoryType.HEAP.name().equals(((Attribute)al.get(0)).getValue()); | ||
| 214 | } | ||
| 215 | PoolPlotter poolPlotter = new PoolPlotter(objectName, name, isHeap); | ||
| 216 | proxyClient.addWeakPropertyChangeListener(poolPlotter); | ||
| 217 | |||
| 218 | poolPlotter.createSequence(usedKey, usedName, usedColor, true); | ||
| 219 | poolPlotter.createSequence(committedKey, committedName, committedColor, false); | ||
| 220 | poolPlotter.createSequence(maxKey, maxName, maxColor, false); | ||
| 221 | poolPlotter.createSequence(thresholdKey, thresholdName, thresholdColor, false); | ||
| 222 | poolPlotter.setUseDashedTransitions(thresholdKey, true); | ||
| 223 | |||
| 224 | if (isHeap) { | ||
| 225 | plotterList.add(poolPlotter); | ||
| 226 | } else { | ||
| 227 | // Will be added to plotterList below | ||
| 228 | nonHeapPlotters.add(poolPlotter); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | ||
| 232 | // Add non-heap plotters last | ||
| 233 | for (PoolPlotter poolPlotter : nonHeapPlotters) { | ||
| 234 | plotterList.add(poolPlotter); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | public void itemStateChanged(ItemEvent ev) { | ||
| 240 | if (ev.getStateChange() == ItemEvent.SELECTED) { | ||
| 241 | Plotter plotter = (Plotter)plotterChoice.getSelectedItem(); | ||
| 242 | plotterPanel.setPlotter(plotter); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | public void gc() { | ||
| 247 | new Thread("MemoryPanel.gc") { | ||
| 248 | public void run() { | ||
| 249 | ProxyClient proxyClient = vmPanel.getProxyClient(); | ||
| 250 | try { | ||
| 251 | proxyClient.getMemoryMXBean().gc(); | ||
| 252 | } catch (UndeclaredThrowableException e) { | ||
| 253 | proxyClient.markAsDead(); | ||
| 254 | } catch (IOException e) { | ||
| 255 | // Ignore | ||
| 256 | } | ||
| 257 | } | ||
| 258 | }.start(); | ||
| 259 | } | ||
| 260 | |||
| 261 | public SwingWorker<?, ?> newSwingWorker() { | ||
| 262 | return new SwingWorker<Boolean, Object>() { | ||
| 263 | private long[] used, committed, max, threshold; | ||
| 264 | private long timeStamp; | ||
| 265 | private String detailsStr; | ||
| 266 | private boolean initialRun = false; | ||
| 267 | |||
| 268 | public Boolean doInBackground() { | ||
| 269 | ProxyClient proxyClient = vmPanel.getProxyClient(); | ||
| 270 | |||
| 271 | if (plotterList == null) { | ||
| 272 | try { | ||
| 273 | createPlotters(); | ||
| 274 | } catch (UndeclaredThrowableException e) { | ||
| 275 | proxyClient.markAsDead(); | ||
| 276 | return false; | ||
| 277 | } catch (final IOException ex) { | ||
| 278 | return false; | ||
| 279 | } | ||
| 280 | initialRun = true; | ||
| 281 | } | ||
| 282 | |||
| 283 | int n = plotterList.size(); | ||
| 284 | used = new long[n]; | ||
| 285 | committed = new long[n]; | ||
| 286 | max = new long[n]; | ||
| 287 | threshold = new long[n]; | ||
| 288 | timeStamp = System.currentTimeMillis(); | ||
| 289 | int poolCount = 0; | ||
| 290 | |||
| 291 | for (int i = 0; i < n; i++) { | ||
| 292 | Plotter plotter = plotterList.get(i); | ||
| 293 | MemoryUsage mu = null; | ||
| 294 | used[i] = -1L; | ||
| 295 | threshold[i] = -1L; | ||
| 296 | |||
| 297 | try { | ||
| 298 | if (plotter instanceof PoolPlotter) { | ||
| 299 | PoolPlotter poolPlotter = (PoolPlotter)plotter; | ||
| 300 | ObjectName objectName = poolPlotter.objectName; | ||
| 301 | AttributeList al = | ||
| 302 | proxyClient.getAttributes(objectName, | ||
| 303 | new String[] { "Usage", "UsageThreshold" }); | ||
| 304 | if (al.size() > 0) { | ||
| 305 | CompositeData cd = (CompositeData)((Attribute)al.get(0)).getValue(); | ||
| 306 | mu = MemoryUsage.from(cd); | ||
| 307 | |||
| 308 | if (al.size() > 1) { | ||
| 309 | threshold[i] = (Long)((Attribute)al.get(1)).getValue(); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } else if (plotter == heapPlotter) { | ||
| 313 | mu = proxyClient.getMemoryMXBean().getHeapMemoryUsage(); | ||
| 314 | } else if (plotter == nonHeapPlotter) { | ||
| 315 | mu = proxyClient.getMemoryMXBean().getNonHeapMemoryUsage(); | ||
| 316 | } | ||
| 317 | } catch (UndeclaredThrowableException e) { | ||
| 318 | proxyClient.markAsDead(); | ||
| 319 | return false; | ||
| 320 | } catch (IOException ex) { | ||
| 321 | // Skip this plotter | ||
| 322 | } | ||
| 323 | |||
| 324 | if (mu != null) { | ||
| 325 | used[i] = mu.getUsed(); | ||
| 326 | committed[i] = mu.getCommitted(); | ||
| 327 | max[i] = mu.getMax(); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | detailsStr = formatDetails(); | ||
| 331 | |||
| 332 | return true; | ||
| 333 | } | ||
| 334 | |||
| 335 | protected void done() { | ||
| 336 | try { | ||
| 337 | if (!get()) { | ||
| 338 | return; | ||
| 339 | } | ||
| 340 | } catch (InterruptedException ex) { | ||
| 341 | return; | ||
| 342 | } catch (ExecutionException ex) { | ||
| 343 | if (JConsole.isDebug()) { | ||
| 344 | ex.printStackTrace(); | ||
| 345 | } | ||
| 346 | return; | ||
| 347 | } | ||
| 348 | |||
| 349 | if (initialRun) { | ||
| 350 | // Add Memory Pools | ||
| 351 | for (Plotter p : plotterList) { | ||
| 352 | plotterChoice.addItem(p); | ||
| 353 | timeComboBox.addPlotter(p); | ||
| 354 | } | ||
| 355 | add(bottomPanel, BorderLayout.SOUTH); | ||
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | int n = plotterList.size(); | ||
| 360 | int poolCount = 0; | ||
| 361 | |||
| 362 | for (int i = 0; i < n; i++) { | ||
| 363 | Plotter plotter = plotterList.get(i); | ||
| 364 | if (used[i] >= 0L) { | ||
| 365 | if (plotter instanceof PoolPlotter) { | ||
| 366 | plotter.addValues(timeStamp, used[i], committed[i], max[i], threshold[i]); | ||
| 367 | if (threshold[i] > 0L) { | ||
| 368 | plotter.setIsPlotted(thresholdKey, true); | ||
| 369 | } | ||
| 370 | poolChart.setValue(poolCount++, (PoolPlotter)plotter, | ||
| 371 | used[i], threshold[i], max[i]); | ||
| 372 | } else { | ||
| 373 | plotter.addValues(timeStamp, used[i], committed[i], max[i]); | ||
| 374 | } | ||
| 375 | |||
| 376 | if (plotter == heapPlotter && overviewPanel != null) { | ||
| 377 | overviewPanel.getPlotter().addValues(timeStamp, used[i]); | ||
| 378 | overviewPanel.updateMemoryInfo(used[i], committed[i], max[i]); | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | details.setText(detailsStr); | ||
| 383 | } | ||
| 384 | }; | ||
| 385 | } | ||
| 386 | |||
| 387 | private String formatDetails() { | ||
| 388 | ProxyClient proxyClient = vmPanel.getProxyClient(); | ||
| 389 | if (proxyClient.isDead()) { | ||
| 390 | return ""; | ||
| 391 | } | ||
| 392 | |||
| 393 | String text = "<table cellspacing=0 cellpadding=0>"; | ||
| 394 | |||
| 395 | Plotter plotter = (Plotter)plotterChoice.getSelectedItem(); | ||
| 396 | if (plotter == null) { | ||
| 397 | return ""; | ||
| 398 | } | ||
| 399 | |||
| 400 | //long time = plotter.getLastTimeStamp(); | ||
| 401 | long time = System.currentTimeMillis(); | ||
| 402 | String timeStamp = formatDateTime(time); | ||
| 403 | text += newRow(getText("Time"), timeStamp); | ||
| 404 | |||
| 405 | long used = plotter.getLastValue(usedKey); | ||
| 406 | long committed = plotter.getLastValue(committedKey); | ||
| 407 | long max = plotter.getLastValue(maxKey); | ||
| 408 | long threshold = plotter.getLastValue(thresholdKey); | ||
| 409 | |||
| 410 | text += newRow(getText("Used"), formatKBytes(used)); | ||
| 411 | if (committed > 0L) { | ||
| 412 | text += newRow(getText("Committed"), formatKBytes(committed)); | ||
| 413 | } | ||
| 414 | if (max > 0L) { | ||
| 415 | text += newRow(getText("Max"), formatKBytes(max)); | ||
| 416 | } | ||
| 417 | if (threshold > 0L) { | ||
| 418 | text += newRow(getText("Usage Threshold"), formatKBytes(threshold)); | ||
| 419 | } | ||
| 420 | |||
| 421 | try { | ||
| 422 | Collection<GarbageCollectorMXBean> garbageCollectors = | ||
| 423 | proxyClient.getGarbageCollectorMXBeans(); | ||
| 424 | |||
| 425 | boolean descPrinted = false; | ||
| 426 | for (GarbageCollectorMXBean garbageCollectorMBean : garbageCollectors) { | ||
| 427 | String gcName = garbageCollectorMBean.getName(); | ||
| 428 | long gcCount = garbageCollectorMBean.getCollectionCount(); | ||
| 429 | long gcTime = garbageCollectorMBean.getCollectionTime(); | ||
| 430 | String str = getText("GC time details", justify(formatTime(gcTime), 14), | ||
| 431 | gcName, | ||
| 432 | String.format("%,d",gcCount)); | ||
| 433 | if (!descPrinted) { | ||
| 434 | text += newRow(getText("GC time"), str); | ||
| 435 | descPrinted = true; | ||
| 436 | } else { | ||
| 437 | text += newRow(null, str); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | } catch (IOException e) { | ||
| 441 | } | ||
| 442 | |||
| 443 | return text; | ||
| 444 | } | ||
| 445 | |||
| 446 | public void actionPerformed(ActionEvent ev) { | ||
| 447 | Object src = ev.getSource(); | ||
| 448 | if (src == gcButton) { | ||
| 449 | gc(); | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | private class PoolPlotter extends Plotter { | ||
| 454 | ObjectName objectName; | ||
| 455 | String name; | ||
| 456 | boolean isHeap; | ||
| 457 | long value, threshold, max; | ||
| 458 | int barX; | ||
| 459 | |||
| 460 | public PoolPlotter(ObjectName objectName, String name, boolean isHeap) { | ||
| 461 | super(Plotter.Unit.BYTES); | ||
| 462 | |||
| 463 | this.objectName = objectName; | ||
| 464 | this.name = name; | ||
| 465 | this.isHeap = isHeap; | ||
| 466 | |||
| 467 | setAccessibleName(this, | ||
| 468 | getText("MemoryTab.poolPlotter.accessibleName", | ||
| 469 | name)); | ||
| 470 | } | ||
| 471 | |||
| 472 | |||
| 473 | public String toString() { | ||
| 474 | return name; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | |||
| 478 | private class PoolChart extends BorderedComponent | ||
| 479 | implements Accessible, MouseListener { | ||
| 480 | final int height = 150; | ||
| 481 | final int leftMargin = 50; | ||
| 482 | final int rightMargin = 23; | ||
| 483 | final int bottomMargin = 35; | ||
| 484 | final int barWidth = 22; | ||
| 485 | final int barGap = 3; | ||
| 486 | final int groupGap = 8; | ||
| 487 | final int barHeight = height * 2 / 3; | ||
| 488 | |||
| 489 | final Color greenBar = new Color(100, 255, 100); | ||
| 490 | final Color greenBarBackground = new Color(210, 255, 210); | ||
| 491 | final Color redBarBackground = new Color(255, 210, 210); | ||
| 492 | |||
| 493 | Font smallFont = null; | ||
| 494 | |||
| 495 | ArrayList<PoolPlotter> poolPlotters = new ArrayList<PoolPlotter>(5); | ||
| 496 | |||
| 497 | int nHeapPools = 0; | ||
| 498 | int nNonHeapPools = 0; | ||
| 499 | Rectangle heapRect = new Rectangle(leftMargin, height - bottomMargin + 6, barWidth, 20); | ||
| 500 | Rectangle nonHeapRect = new Rectangle(leftMargin + groupGap, height - bottomMargin + 6, barWidth, 20); | ||
| 501 | |||
| 502 | public PoolChart() { | ||
| 503 | super(null, null); | ||
| 504 | |||
| 505 | setFocusable(true); | ||
| 506 | addMouseListener(this); | ||
| 507 | ToolTipManager.sharedInstance().registerComponent(this); | ||
| 508 | } | ||
| 509 | |||
| 510 | public void setValue(int poolIndex, PoolPlotter poolPlotter, | ||
| 511 | long value, long threshold, long max) { | ||
| 512 | poolPlotter.value = value; | ||
| 513 | poolPlotter.threshold = threshold; | ||
| 514 | poolPlotter.max = max; | ||
| 515 | |||
| 516 | if (poolIndex == poolPlotters.size()) { | ||
| 517 | poolPlotters.add(poolPlotter); | ||
| 518 | if (poolPlotter.isHeap) { | ||
| 519 | poolPlotter.barX = nHeapPools * (barWidth + barGap); | ||
| 520 | nHeapPools++; | ||
| 521 | heapRect.width = nHeapPools * barWidth + (nHeapPools - 1) * barGap; | ||
| 522 | nonHeapRect.x = leftMargin + heapRect.width + groupGap; | ||
| 523 | } else { | ||
| 524 | poolPlotter.barX = nonHeapRect.x - leftMargin + nNonHeapPools * (barWidth + barGap); | ||
| 525 | nNonHeapPools++; | ||
| 526 | nonHeapRect.width = nNonHeapPools * barWidth + (nNonHeapPools - 1) * barGap; | ||
| 527 | } | ||
| 528 | } else { | ||
| 529 | poolPlotters.set(poolIndex, poolPlotter); | ||
| 530 | } | ||
| 531 | repaint(); | ||
| 532 | } | ||
| 533 | |||
| 534 | private void paintPoolBar(Graphics g, PoolPlotter poolPlotter) { | ||
| 535 | Rectangle barRect = getBarRect(poolPlotter); | ||
| 536 | g.setColor(Color.gray); | ||
| 537 | g.drawRect(barRect.x, barRect.y, barRect.width, barRect.height); | ||
| 538 | |||
| 539 | long value = poolPlotter.value; | ||
| 540 | long max = poolPlotter.max; | ||
| 541 | if (max > 0L) { | ||
| 542 | g.translate(barRect.x, barRect.y); | ||
| 543 | |||
| 544 | // Paint green background | ||
| 545 | g.setColor(greenBarBackground); | ||
| 546 | g.fillRect(1, 1, barRect.width - 1, barRect.height - 1); | ||
| 547 | |||
| 548 | int greenHeight = (int)(value * barRect.height / max); | ||
| 549 | long threshold = poolPlotter.threshold; | ||
| 550 | if (threshold > 0L) { | ||
| 551 | int redHeight = (int)(threshold * barRect.height / max); | ||
| 552 | |||
| 553 | // Paint red background | ||
| 554 | g.setColor(redBarBackground); | ||
| 555 | g.fillRect(1, 1, barRect.width - 1, barRect.height - redHeight); | ||
| 556 | |||
| 557 | if (value > threshold) { | ||
| 558 | // Over threshold, paint red bar | ||
| 559 | g.setColor(thresholdColor); | ||
| 560 | g.fillRect(1, barRect.height - greenHeight, | ||
| 561 | barRect.width - 1, greenHeight - redHeight); | ||
| 562 | greenHeight = redHeight; | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 566 | // Paint green bar | ||
| 567 | g.setColor(greenBar); | ||
| 568 | g.fillRect(1, barRect.height - greenHeight, | ||
| 569 | barRect.width - 1, greenHeight); | ||
| 570 | |||
| 571 | g.translate(-barRect.x, -barRect.y); | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | public void paintComponent(Graphics g) { | ||
| 576 | super.paintComponent(g); | ||
| 577 | |||
| 578 | if (poolPlotters.size() == 0) { | ||
| 579 | return; | ||
| 580 | } | ||
| 581 | |||
| 582 | if (smallFont == null) { | ||
| 583 | smallFont = g.getFont().deriveFont(9.0F); | ||
| 584 | } | ||
| 585 | |||
| 586 | // Paint background for chart area | ||
| 587 | g.setColor(getBackground()); | ||
| 588 | Rectangle r = g.getClipBounds(); | ||
| 589 | g.fillRect(r.x, r.y, r.width, r.height); | ||
| 590 | |||
| 591 | g.setFont(smallFont); | ||
| 592 | FontMetrics fm = g.getFontMetrics(); | ||
| 593 | int fontDescent = fm.getDescent(); | ||
| 594 | |||
| 595 | // Paint percentage axis | ||
| 596 | g.setColor(getForeground()); | ||
| 597 | for (int pc : new int[] { 0, 25, 50, 75, 100 }) { | ||
| 598 | String str = pc + "% --"; | ||
| 599 | g.drawString(str, | ||
| 600 | leftMargin - fm.stringWidth(str) - 4, | ||
| 601 | height - bottomMargin - (pc * barHeight / 100) + fontDescent + 1); | ||
| 602 | } | ||
| 603 | |||
| 604 | for (PoolPlotter poolPlotter : poolPlotters) { | ||
| 605 | paintPoolBar(g, poolPlotter); | ||
| 606 | } | ||
| 607 | |||
| 608 | g.setColor(Color.gray); | ||
| 609 | g.drawRect(heapRect.x, heapRect.y, heapRect.width, heapRect.height); | ||
| 610 | g.drawRect(nonHeapRect.x, nonHeapRect.y, nonHeapRect.width, nonHeapRect.height); | ||
| 611 | |||
| 612 | Color heapColor = greenBar; | ||
| 613 | Color nonHeapColor = greenBar; | ||
| 614 | |||
| 615 | |||
| 616 | for (PoolPlotter poolPlotter : poolPlotters) { | ||
| 617 | if (poolPlotter.threshold > 0L && poolPlotter.value > poolPlotter.threshold) { | ||
| 618 | if (poolPlotter.isHeap) { | ||
| 619 | heapColor = thresholdColor; | ||
| 620 | } else { | ||
| 621 | nonHeapColor = thresholdColor; | ||
| 622 | } | ||
| 623 | } | ||
| 624 | } | ||
| 625 | g.setColor(heapColor); | ||
| 626 | g.fillRect(heapRect.x + 1, heapRect.y + 1, heapRect.width - 1, heapRect.height - 1); | ||
| 627 | g.setColor(nonHeapColor); | ||
| 628 | g.fillRect(nonHeapRect.x + 1, nonHeapRect.y + 1, nonHeapRect.width - 1, nonHeapRect.height - 1); | ||
| 629 | |||
| 630 | String str = getText("Heap"); | ||
| 631 | int stringWidth = fm.stringWidth(str); | ||
| 632 | int x = heapRect.x + (heapRect.width - stringWidth) / 2; | ||
| 633 | int y = heapRect.y + heapRect.height - 6; | ||
| 634 | g.setColor(Color.white); | ||
| 635 | g.drawString(str, x-1, y-1); | ||
| 636 | g.drawString(str, x+1, y-1); | ||
| 637 | g.drawString(str, x-1, y+1); | ||
| 638 | g.drawString(str, x+1, y+1); | ||
| 639 | g.setColor(Color.black); | ||
| 640 | g.drawString(str, x, y); | ||
| 641 | |||
| 642 | str = getText("Non-Heap"); | ||
| 643 | stringWidth = fm.stringWidth(str); | ||
| 644 | x = nonHeapRect.x + (nonHeapRect.width - stringWidth) / 2; | ||
| 645 | y = nonHeapRect.y + nonHeapRect.height - 6; | ||
| 646 | g.setColor(Color.white); | ||
| 647 | g.drawString(str, x-1, y-1); | ||
| 648 | g.drawString(str, x+1, y-1); | ||
| 649 | g.drawString(str, x-1, y+1); | ||
| 650 | g.drawString(str, x+1, y+1); | ||
| 651 | g.setColor(Color.black); | ||
| 652 | g.drawString(str, x, y); | ||
| 653 | |||
| 654 | // Highlight current plotter | ||
| 655 | g.setColor(Color.blue); | ||
| 656 | r = null; | ||
| 657 | Plotter plotter = (Plotter)plotterChoice.getSelectedItem(); | ||
| 658 | if (plotter == heapPlotter) { | ||
| 659 | r = heapRect; | ||
| 660 | } else if (plotter == nonHeapPlotter) { | ||
| 661 | r = nonHeapRect; | ||
| 662 | } else if (plotter instanceof PoolPlotter) { | ||
| 663 | r = getBarRect((PoolPlotter)plotter); | ||
| 664 | } | ||
| 665 | if (r != null) { | ||
| 666 | g.drawRect(r.x - 1, r.y - 1, r.width + 2, r.height + 2); | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | private Rectangle getBarRect(PoolPlotter poolPlotter) { | ||
| 671 | return new Rectangle(leftMargin + poolPlotter.barX, | ||
| 672 | height - bottomMargin - barHeight, | ||
| 673 | barWidth, barHeight); | ||
| 674 | } | ||
| 675 | |||
| 676 | public Dimension getPreferredSize() { | ||
| 677 | return new Dimension(nonHeapRect.x + nonHeapRect.width + rightMargin, | ||
| 678 | height); | ||
| 679 | } | ||
| 680 | |||
| 681 | public void mouseClicked(MouseEvent e) { | ||
| 682 | requestFocusInWindow(); | ||
| 683 | Plotter plotter = getPlotter(e); | ||
| 684 | |||
| 685 | if (plotter != null && plotter != plotterChoice.getSelectedItem()) { | ||
| 686 | plotterChoice.setSelectedItem(plotter); | ||
| 687 | repaint(); | ||
| 688 | } | ||
| 689 | } | ||
| 690 | |||
| 691 | public String getToolTipText(MouseEvent e) { | ||
| 692 | Plotter plotter = getPlotter(e); | ||
| 693 | |||
| 694 | return (plotter != null) ? plotter.toString() : null; | ||
| 695 | } | ||
| 696 | |||
| 697 | private Plotter getPlotter(MouseEvent e) { | ||
| 698 | Point p = e.getPoint(); | ||
| 699 | Plotter plotter = null; | ||
| 700 | |||
| 701 | if (heapRect.contains(p)) { | ||
| 702 | plotter = heapPlotter; | ||
| 703 | } else if (nonHeapRect.contains(p)) { | ||
| 704 | plotter = nonHeapPlotter; | ||
| 705 | } else { | ||
| 706 | for (PoolPlotter poolPlotter : poolPlotters) { | ||
| 707 | if (getBarRect(poolPlotter).contains(p)) { | ||
| 708 | plotter = poolPlotter; | ||
| 709 | break; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | } | ||
| 713 | return plotter; | ||
| 714 | } | ||
| 715 | |||
| 716 | public void mousePressed(MouseEvent e) {} | ||
| 717 | public void mouseReleased(MouseEvent e) {} | ||
| 718 | public void mouseEntered(MouseEvent e) {} | ||
| 719 | public void mouseExited(MouseEvent e) {} | ||
| 720 | |||
| 721 | |||
| 722 | public AccessibleContext getAccessibleContext() { | ||
| 723 | if (accessibleContext == null) { | ||
| 724 | accessibleContext = new AccessiblePoolChart(); | ||
| 725 | } | ||
| 726 | return accessibleContext; | ||
| 727 | } | ||
| 728 | |||
| 729 | protected class AccessiblePoolChart extends AccessibleJPanel { | ||
| 730 | public String getAccessibleName() { | ||
| 731 | String name = getText("MemoryTab.poolChart.accessibleName"); | ||
| 732 | |||
| 733 | String keyValueList = ""; | ||
| 734 | for (PoolPlotter poolPlotter : poolPlotters) { | ||
| 735 | String value = (poolPlotter.value * 100 / poolPlotter.max) + "%"; | ||
| 736 | // Assume format string ends with newline | ||
| 737 | keyValueList += | ||
| 738 | getText("Plotter.accessibleName.keyAndValue", | ||
| 739 | poolPlotter.toString(), value); | ||
| 740 | if (poolPlotter.threshold > 0L) { | ||
| 741 | String threshold = | ||
| 742 | (poolPlotter.threshold * 100 / poolPlotter.max) + "%"; | ||
| 743 | if (poolPlotter.value > poolPlotter.threshold) { | ||
| 744 | keyValueList += | ||
| 745 | getText("MemoryTab.poolChart.aboveThreshold", | ||
| 746 | threshold); | ||
| 747 | } else { | ||
| 748 | keyValueList += | ||
| 749 | getText("MemoryTab.poolChart.belowThreshold", | ||
| 750 | threshold); | ||
| 751 | } | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | return name + "\n" + keyValueList + "."; | ||
| 756 | } | ||
| 757 | } | ||
| 758 | } | ||
| 759 | |||
| 760 | |||
| 761 | OverviewPanel[] getOverviewPanels() { | ||
| 762 | if (overviewPanel == null) { | ||
| 763 | overviewPanel = new MemoryOverviewPanel(); | ||
| 764 | } | ||
| 765 | return new OverviewPanel[] { overviewPanel }; | ||
| 766 | } | ||
| 767 | |||
| 768 | private static class MemoryOverviewPanel extends OverviewPanel { | ||
| 769 | MemoryOverviewPanel() { | ||
| 770 | super(getText("Heap Memory Usage"), usedKey, usedName, Plotter.Unit.BYTES); | ||
| 771 | } | ||
| 772 | |||
| 773 | private void updateMemoryInfo(long used, long committed, long max) { | ||
| 774 | getInfoLabel().setText(getText(infoLabelFormat, | ||
| 775 | formatBytes(used, true), | ||
| 776 | formatBytes(committed, true), | ||
| 777 | formatBytes(max, true))); | ||
| 778 | } | ||
| 779 | } | ||
| 780 | } | ||