1 /*
   2  *
   3  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  *   - Redistributions of source code must retain the above copyright
  10  *     notice, this list of conditions and the following disclaimer.
  11  *
  12  *   - Redistributions in binary form must reproduce the above copyright
  13  *     notice, this list of conditions and the following disclaimer in the
  14  *     documentation and/or other materials provided with the distribution.
  15  *
  16  *   - Neither the name of Oracle nor the names of its
  17  *     contributors may be used to endorse or promote products derived
  18  *     from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 package java2d;
  33 
  34 
  35 import static java.awt.Color.BLACK;
  36 import static java.awt.Color.GREEN;
  37 import static java.awt.Color.YELLOW;
  38 import java.awt.BorderLayout;
  39 import java.awt.Color;
  40 import java.awt.Dimension;
  41 import java.awt.Font;
  42 import java.awt.FontMetrics;
  43 import java.awt.Graphics;
  44 import java.awt.Graphics2D;
  45 import java.awt.Rectangle;
  46 import java.awt.event.MouseAdapter;
  47 import java.awt.event.MouseEvent;
  48 import java.awt.event.WindowAdapter;
  49 import java.awt.event.WindowEvent;
  50 import java.awt.event.WindowListener;
  51 import java.awt.geom.Line2D;
  52 import java.awt.geom.Rectangle2D;
  53 import java.awt.image.BufferedImage;
  54 import java.util.Date;
  55 import javax.swing.JCheckBox;
  56 import javax.swing.JFrame;
  57 import javax.swing.JLabel;
  58 import javax.swing.JPanel;
  59 import javax.swing.JTextField;
  60 import javax.swing.border.EtchedBorder;
  61 import javax.swing.border.TitledBorder;
  62 
  63 
  64 /**
  65  * Tracks Memory allocated & used, displayed in graph form.
  66  */
  67 @SuppressWarnings("serial")
  68 public class MemoryMonitor extends JPanel {
  69 
  70     private final JCheckBox dateStampCB = new JCheckBox("Output Date Stamp");
  71     public Surface surf;
  72     JPanel controls;
  73     boolean doControls;
  74     JTextField tf;
  75 
  76     public MemoryMonitor() {
  77         setLayout(new BorderLayout());
  78         setBorder(new TitledBorder(new EtchedBorder(), "Memory Monitor"));
  79         add(surf = new Surface());
  80         controls = new JPanel();
  81         controls.setPreferredSize(new Dimension(135, 80));
  82         Font font = new Font(Font.SERIF, Font.PLAIN, 10);
  83         JLabel label = new JLabel("Sample Rate");
  84         label.setFont(font);
  85         label.setForeground(BLACK);
  86         controls.add(label);
  87         tf = new JTextField("1000");
  88         tf.setPreferredSize(new Dimension(45, 20));
  89         controls.add(tf);
  90         controls.add(label = new JLabel("ms"));
  91         label.setFont(font);
  92         label.setForeground(BLACK);
  93         controls.add(dateStampCB);
  94         dateStampCB.setFont(font);
  95         addMouseListener(new MouseAdapter() {
  96 
  97             @Override
  98             public void mouseClicked(MouseEvent e) {
  99                 removeAll();
 100                 if ((doControls = !doControls)) {
 101                     surf.stop();
 102                     add(controls);
 103                 } else {
 104                     try {
 105                         surf.sleepAmount = Long.parseLong(tf.getText().trim());
 106                     } catch (Exception ex) {
 107                     }
 108                     surf.start();
 109                     add(surf);
 110                 }
 111                 revalidate();
 112                 repaint();
 113             }
 114         });
 115     }
 116 
 117 
 118     public class Surface extends JPanel implements Runnable {
 119 
 120         public Thread thread;
 121         public long sleepAmount = 1000;
 122         private int w, h;
 123         private BufferedImage bimg;
 124         private Graphics2D big;
 125         private Font font = new Font(Font.SERIF, Font.PLAIN, 11);
 126         private Runtime r = Runtime.getRuntime();
 127         private int columnInc;
 128         private int pts[];
 129         private int ptNum;
 130         private int ascent, descent;
 131         private Rectangle graphOutlineRect = new Rectangle();
 132         private Rectangle2D mfRect = new Rectangle2D.Float();
 133         private Rectangle2D muRect = new Rectangle2D.Float();
 134         private Line2D graphLine = new Line2D.Float();
 135         private Color graphColor = new Color(46, 139, 87);
 136         private Color mfColor = new Color(0, 100, 0);
 137         private String usedStr;
 138 
 139         public Surface() {
 140             setBackground(BLACK);
 141             addMouseListener(new MouseAdapter() {
 142 
 143                 @Override
 144                 public void mouseClicked(MouseEvent e) {
 145                     if (thread == null) {
 146                         start();
 147                     } else {
 148                         stop();
 149                     }
 150                 }
 151             });
 152         }
 153 
 154         @Override
 155         public Dimension getMinimumSize() {
 156             return getPreferredSize();
 157         }
 158 
 159         @Override
 160         public Dimension getMaximumSize() {
 161             return getPreferredSize();
 162         }
 163 
 164         @Override
 165         public Dimension getPreferredSize() {
 166             return new Dimension(135, 80);
 167         }
 168 
 169         @Override
 170         public void paint(Graphics g) {
 171 
 172             if (big == null) {
 173                 return;
 174             }
 175 
 176             big.setBackground(getBackground());
 177             big.clearRect(0, 0, w, h);
 178 
 179             float freeMemory = r.freeMemory();
 180             float totalMemory = r.totalMemory();
 181 
 182             // .. Draw allocated and used strings ..
 183             big.setColor(GREEN);
 184             big.drawString(String.valueOf((int) totalMemory / 1024)
 185                     + "K allocated", 4.0f, ascent + 0.5f);
 186             usedStr = String.valueOf(((int) (totalMemory - freeMemory)) / 1024)
 187                     + "K used";
 188             big.drawString(usedStr, 4, h - descent);
 189 
 190             // Calculate remaining size
 191             float ssH = ascent + descent;
 192             float remainingHeight = (h - (ssH * 2) - 0.5f);
 193             float blockHeight = remainingHeight / 10;
 194             float blockWidth = 20.0f;
 195 
 196             // .. Memory Free ..
 197             big.setColor(mfColor);
 198             int MemUsage = (int) ((freeMemory / totalMemory) * 10);
 199             int i = 0;
 200             for (; i < MemUsage; i++) {
 201                 mfRect.setRect(5, ssH + i * blockHeight,
 202                         blockWidth, blockHeight - 1);
 203                 big.fill(mfRect);
 204             }
 205 
 206             // .. Memory Used ..
 207             big.setColor(GREEN);
 208             for (; i < 10; i++) {
 209                 muRect.setRect(5, ssH + i * blockHeight,
 210                         blockWidth, blockHeight - 1);
 211                 big.fill(muRect);
 212             }
 213 
 214             // .. Draw History Graph ..
 215             big.setColor(graphColor);
 216             int graphX = 30;
 217             int graphY = (int) ssH;
 218             int graphW = w - graphX - 5;
 219             int graphH = (int) remainingHeight;
 220             graphOutlineRect.setRect(graphX, graphY, graphW, graphH);
 221             big.draw(graphOutlineRect);
 222 
 223             int graphRow = graphH / 10;
 224 
 225             // .. Draw row ..
 226             for (int j = graphY; j <= graphH + graphY; j += graphRow) {
 227                 graphLine.setLine(graphX, j, graphX + graphW, j);
 228                 big.draw(graphLine);
 229             }
 230 
 231             // .. Draw animated column movement ..
 232             int graphColumn = graphW / 15;
 233 
 234             if (columnInc == 0) {
 235                 columnInc = graphColumn;
 236             }
 237 
 238             for (int j = graphX + columnInc; j < graphW + graphX; j +=
 239                             graphColumn) {
 240                 graphLine.setLine(j, graphY, j, graphY + graphH);
 241                 big.draw(graphLine);
 242             }
 243 
 244             --columnInc;
 245 
 246             if (pts == null) {
 247                 pts = new int[graphW];
 248                 ptNum = 0;
 249             } else if (pts.length != graphW) {
 250                 int tmp[] = null;
 251                 if (ptNum < graphW) {
 252                     tmp = new int[ptNum];
 253                     System.arraycopy(pts, 0, tmp, 0, tmp.length);
 254                 } else {
 255                     tmp = new int[graphW];
 256                     System.arraycopy(pts, pts.length - tmp.length, tmp, 0,
 257                             tmp.length);
 258                     ptNum = tmp.length - 2;
 259                 }
 260                 pts = new int[graphW];
 261                 System.arraycopy(tmp, 0, pts, 0, tmp.length);
 262             } else {
 263                 big.setColor(YELLOW);
 264                 pts[ptNum] =
 265                         (int) (graphY + graphH * (freeMemory / totalMemory));
 266                 for (int j = graphX + graphW - ptNum, k = 0; k < ptNum; k++, j++) {
 267                     if (k != 0) {
 268                         if (pts[k] != pts[k - 1]) {
 269                             big.drawLine(j - 1, pts[k - 1], j, pts[k]);
 270                         } else {
 271                             big.fillRect(j, pts[k], 1, 1);
 272                         }
 273                     }
 274                 }
 275                 if (ptNum + 2 == pts.length) {
 276                     // throw out oldest point
 277                     for (int j = 1; j < ptNum; j++) {
 278                         pts[j - 1] = pts[j];
 279                     }
 280                     --ptNum;
 281                 } else {
 282                     ptNum++;
 283                 }
 284             }
 285             g.drawImage(bimg, 0, 0, this);
 286         }
 287 
 288         public void start() {
 289             thread = new Thread(this);
 290             thread.setPriority(Thread.MIN_PRIORITY);
 291             thread.setName("MemoryMonitor");
 292             thread.start();
 293         }
 294 
 295         public synchronized void stop() {
 296             thread = null;
 297             notify();
 298         }
 299 
 300         @Override
 301         @SuppressWarnings("SleepWhileHoldingLock")
 302         public void run() {
 303 
 304             Thread me = Thread.currentThread();
 305 
 306             while (thread == me && !isShowing() || getSize().width == 0) {
 307                 try {
 308                     Thread.sleep(500);
 309                 } catch (InterruptedException e) {
 310                     return;
 311                 }
 312             }
 313 
 314             while (thread == me && isShowing()) {
 315                 Dimension d = getSize();
 316                 if (d.width != w || d.height != h) {
 317                     w = d.width;
 318                     h = d.height;
 319                     bimg = (BufferedImage) createImage(w, h);
 320                     big = bimg.createGraphics();
 321                     big.setFont(font);
 322                     FontMetrics fm = big.getFontMetrics(font);
 323                     ascent = fm.getAscent();
 324                     descent = fm.getDescent();
 325                 }
 326                 repaint();
 327                 try {
 328                     Thread.sleep(sleepAmount);
 329                 } catch (InterruptedException e) {
 330                     break;
 331                 }
 332                 if (dateStampCB.isSelected()) {
 333                     System.out.println(new Date().toString() + " " + usedStr);
 334                 }
 335             }
 336             thread = null;
 337         }
 338     }
 339 
 340     public static void main(String s[]) {
 341         final MemoryMonitor demo = new MemoryMonitor();
 342         WindowListener l = new WindowAdapter() {
 343 
 344             @Override
 345             public void windowClosing(WindowEvent e) {
 346                 System.exit(0);
 347             }
 348 
 349             @Override
 350             public void windowDeiconified(WindowEvent e) {
 351                 demo.surf.start();
 352             }
 353 
 354             @Override
 355             public void windowIconified(WindowEvent e) {
 356                 demo.surf.stop();
 357             }
 358         };
 359         JFrame f = new JFrame("J2D Demo - MemoryMonitor");
 360         f.addWindowListener(l);
 361         f.getContentPane().add("Center", demo);
 362         f.pack();
 363         f.setSize(new Dimension(200, 200));
 364         f.setVisible(true);
 365         demo.surf.start();
 366     }
 367 }