001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.system; 020 021import java.awt.BasicStroke; 022import java.awt.Color; 023import java.awt.Dimension; 024import java.awt.Font; 025import java.awt.Graphics; 026import java.awt.Graphics2D; 027import java.awt.Image; 028import java.awt.RenderingHints; 029import java.awt.event.MouseEvent; 030import java.awt.event.MouseListener; 031import java.awt.image.BufferedImage; 032import java.util.Timer; 033import java.util.TimerTask; 034 035import javax.swing.JPanel; 036 037import icy.image.ImageUtil; 038import icy.image.cache.ImageCache; 039import icy.math.UnitUtil; 040import icy.network.NetworkUtil; 041import icy.resource.ResourceUtil; 042import icy.system.SystemUtil; 043import icy.system.thread.ThreadUtil; 044import icy.util.ColorUtil; 045import icy.util.GraphicsUtil; 046import vtk.vtkObjectBase; 047 048/** 049 * Memory monitor. 050 * 051 * @author Fab & Stephane 052 */ 053public class MemoryMonitorPanel extends JPanel implements MouseListener 054{ 055 private static final long serialVersionUID = 5629509450385435829L; 056 057 private static int NBVAL = 94; 058 059 /** 060 * 0 est la valeur la plus ancienne. 061 */ 062 private final double[][] valeur; 063 private final String[] infos; 064 private final Timer updateTimer; 065 066 private final Color cacheTextColor = ColorUtil.mix(Color.yellow, Color.white); 067 private final Color cpuColor = ColorUtil.mix(Color.blue, Color.white); 068 private final Color cpuTextColor = ColorUtil.mix(cpuColor, Color.white); 069 private final Color memColor = Color.green; 070 private final Color memTextColor = ColorUtil.mix(memColor, Color.white); 071 private final Color connectionColor = ColorUtil.mix(Color.red, Color.white); 072 private final BasicStroke cpuStroke = new BasicStroke(2); 073 private final BasicStroke memStroke = new BasicStroke(3); 074 private final Font textFont = new Font("Arial", Font.BOLD, 9); 075 private BufferedImage background = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); 076 private final Image networkImage = ImageUtil.getColorImageFromAlphaImage(ResourceUtil.ICON_NETWORK, Color.gray); 077 private final Image deleteImage = ImageUtil.getColorImageFromAlphaImage(ResourceUtil.ICON_DELETE, Color.red); 078 079 boolean displayHelpMessage = false; 080 int lastCacheUpdate; 081 082 public MemoryMonitorPanel() 083 { 084 super(); 085 086 updateTimer = new Timer("Memory / CPU monitor"); 087 088 // init tables 089 valeur = new double[NBVAL][2]; 090 for (int i = 0; i < NBVAL; i++) 091 { 092 // mem 093 valeur[i][0] = 0; 094 // cpu load 095 valeur[i][1] = 0; 096 } 097 infos = new String[3]; 098 for (int i = 0; i < 2; i++) 099 infos[i] = ""; 100 101 lastCacheUpdate = 10; 102 103 setMinimumSize(new Dimension(120, 50)); 104 setPreferredSize(new Dimension(140, 55)); 105 106 addMouseListener(this); 107 108 updateTimer.scheduleAtFixedRate(new TimerTask() 109 { 110 @Override 111 public void run() 112 { 113 updateStats(); 114 } 115 }, 100, 100); 116 } 117 118 @Override 119 protected void paintComponent(Graphics g) 120 { 121 final Graphics2D g2 = (Graphics2D) g.create(); 122 123 final int w = getWidth(); 124 final int h = getHeight(); 125 126 // refresh BG 127 if ((background.getWidth() != w) || (background.getHeight() != h)) 128 { 129 background = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 130 Graphics2D background_g2 = background.createGraphics(); 131 GraphicsUtil.paintIcyBackGround(w, h, background_g2); 132 } 133 134 // draw cached BG 135 g2.drawImage(background, 0, 0, null); 136 137 // enabled AA 138 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 139 140 // display graph 141 if (valeur != null) 142 { 143 float x; 144 double max; 145 double ymul; 146 final float step = w / 100f; 147 148 // draw used memory 149 g2.setStroke(memStroke); 150 g2.setColor(memColor); 151 152 max = SystemUtil.getJavaMaxMemory(); 153 ymul = (h - 8) / max; 154 x = 6; 155 for (int i = 0; i < NBVAL - 1; i++) 156 { 157 final double v1 = Math.min(valeur[i][0], max); 158 final double v2 = Math.min(valeur[i + 1][0], max); 159 final int y1 = h - (int) (v1 * ymul); 160 final int y2 = h - (int) (v2 * ymul); 161 g2.drawLine((int) x, y1 - 4, (int) (x + step), y2 - 4); 162 x += step; 163 } 164 165 // draw CPU load 166 g2.setStroke(cpuStroke); 167 g2.setColor(cpuColor); 168 169 max = 100d; 170 ymul = (h - 8) / max; 171 x = 6; 172 for (int i = 0; i < NBVAL - 1; i++) 173 { 174 final double v1 = Math.min(valeur[i][1], max); 175 final double v2 = Math.min(valeur[i + 1][1], max); 176 final int y1 = h - (int) (v1 * ymul); 177 final int y2 = h - (int) (v2 * ymul); 178 g2.drawLine((int) x, y1 - 4, (int) (x + step), y2 - 4); 179 x += step; 180 } 181 } 182 183 // display text 184 g2.setFont(textFont); 185 186 // display Used & Max Memory 187 g2.setColor(Color.black); 188 GraphicsUtil.drawHCenteredString(g2, infos[0], (w / 2) + 1, 6 + 1, false); 189 g2.setColor(memTextColor); 190 GraphicsUtil.drawHCenteredString(g2, infos[0], w / 2, 6, false); 191 // display CPU Load 192 g2.setColor(Color.black); 193 GraphicsUtil.drawHCenteredString(g2, infos[1], (w / 2) + 1, 18 + 1, false); 194 g2.setColor(cpuTextColor); 195 GraphicsUtil.drawHCenteredString(g2, infos[1], w / 2, 18, false); 196 // display cache Load 197 g2.setColor(Color.black); 198 GraphicsUtil.drawHCenteredString(g2, infos[2], (w / 2) + 1, 30 + 1, false); 199 g2.setColor(cacheTextColor); 200 GraphicsUtil.drawHCenteredString(g2, infos[2], w / 2, 30, false); 201 202 String text; 203 204 // display internet connection 205 if (!NetworkUtil.hasInternetAccess()) 206 { 207 g2.drawImage(networkImage, 10, 30, 16, 16, null); 208 g2.drawImage(deleteImage, 13, 35, 10, 10, null); 209 210 if (displayHelpMessage) 211 { 212 text = "Not connected to internet"; 213 214 g2.setColor(Color.black); 215 GraphicsUtil.drawHCenteredString(g2, text, (w / 2) + 1, 30 + 1, false); 216 g2.setColor(connectionColor); 217 GraphicsUtil.drawHCenteredString(g2, text, w / 2, 30, false); 218 } 219 } 220 221 if (displayHelpMessage) 222 { 223 text = "click to force a garbage collector event"; 224 g2.setColor(Color.black); 225 GraphicsUtil.drawHCenteredString(g2, text, (w / 2) + 1, 44 + 1, false); 226 g2.setColor(Color.white); 227 GraphicsUtil.drawHCenteredString(g2, text, w / 2, 44, false); 228 } 229 230 g2.dispose(); 231 } 232 233 void updateStats() 234 { 235 final double usedMemory = SystemUtil.getJavaUsedMemory(); 236 final int cpuLoad = SystemUtil.getCpuLoad(); 237 238 // save used memory 239 newValue(0, usedMemory); 240 // save CPU load 241 newValue(1, cpuLoad); 242 243 setInfo(0, "Memory: " + UnitUtil.getBytesString(usedMemory) + " / " 244 + UnitUtil.getBytesString(SystemUtil.getJavaMaxMemory())); 245 setInfo(1, "CPU: " + cpuLoad + "%"); 246 if (ImageCache.isEnabled()) 247 { 248 // don't update cache stats (take sometime) at each frame 249 if (--lastCacheUpdate == 0) 250 { 251 try 252 { 253 setInfo(2, "Cache - Memory: " + UnitUtil.getBytesString(ImageCache.usedMemory()) + " Disk: " 254 + UnitUtil.getBytesString(ImageCache.usedDisk())); 255 } 256 catch(Throwable t) 257 { 258 // can happen when we exit Icy as the cache engine may be shutdown 259 // we can ignore safely 260 } 261 262 lastCacheUpdate = 10; 263 } 264 } 265 else 266 setInfo(2, "Cache disabled"); 267 268 repaint(); 269 } 270 271 /** 272 * Scroll les valeurs et en ajoute ( un seeker serait plus joli...) 273 */ 274 public void newValue(int curve, double val) 275 { 276 for (int i = 0; i < NBVAL - 1; i++) 277 valeur[i][curve] = valeur[i + 1][curve]; 278 279 valeur[NBVAL - 1][curve] = val; 280 } 281 282 public void setInfo(int infonb, String info) 283 { 284 infos[infonb] = info; 285 } 286 287 @Override 288 public void mouseClicked(MouseEvent event) 289 { 290 final MouseEvent e = event; 291 292 ThreadUtil.bgRun(new Runnable() 293 { 294 @Override 295 public void run() 296 { 297 final double freeBefore = SystemUtil.getJavaFreeMemory(); 298 299 // force garbage collector 300 System.gc(); 301 302 final double freeAfter = SystemUtil.getJavaFreeMemory(); 303 final double released = freeAfter - freeBefore; 304 final double usedMemory = SystemUtil.getJavaUsedMemory(); 305 306 System.out.println("Max / Used memory: " + UnitUtil.getBytesString(SystemUtil.getJavaMaxMemory()) 307 + " / " + UnitUtil.getBytesString((usedMemory > 0) ? usedMemory : 0) + " (released by GC: " 308 + UnitUtil.getBytesString((released > 0) ? released : 0) + ")"); 309 } 310 }); 311 312 // double click --> force VTK garbage collection (need to be done in EDT or it crashes on OSX) 313 if (e.getClickCount() > 1) 314 { 315 vtkObjectBase.JAVA_OBJECT_MANAGER.gc(true); 316 System.out.println("VTK GC forced"); 317 } 318 } 319 320 @Override 321 public void mouseEntered(MouseEvent arg0) 322 { 323 displayHelpMessage = true; 324 } 325 326 @Override 327 public void mouseExited(MouseEvent arg0) 328 { 329 displayHelpMessage = false; 330 } 331 332 @Override 333 public void mousePressed(MouseEvent arg0) 334 { 335 336 } 337 338 @Override 339 public void mouseReleased(MouseEvent arg0) 340 { 341 342 } 343}