1 | /* |
---|
2 | * This program is free software; you can redistribute it and/or modify |
---|
3 | * it under the terms of the GNU General Public License as published by |
---|
4 | * the Free Software Foundation; either version 2 of the License, or |
---|
5 | * (at your option) any later version. |
---|
6 | * |
---|
7 | * This program is distributed in the hope that it will be useful, |
---|
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
10 | * GNU General Public License for more details. |
---|
11 | * |
---|
12 | * You should have received a copy of the GNU General Public License |
---|
13 | * along with this program; if not, write to the Free Software |
---|
14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | * MemoryUsagePanel.java |
---|
19 | * Copyright (C) 2008 University of Waikato, Hamilton, New Zealand |
---|
20 | */ |
---|
21 | |
---|
22 | package weka.gui; |
---|
23 | |
---|
24 | import weka.core.Memory; |
---|
25 | import weka.core.Utils; |
---|
26 | import weka.gui.visualize.VisualizeUtils; |
---|
27 | |
---|
28 | import java.awt.BorderLayout; |
---|
29 | import java.awt.Color; |
---|
30 | import java.awt.Dimension; |
---|
31 | import java.awt.Graphics; |
---|
32 | import java.awt.Point; |
---|
33 | import java.awt.event.ActionEvent; |
---|
34 | import java.awt.event.ActionListener; |
---|
35 | import java.util.Collections; |
---|
36 | import java.util.Enumeration; |
---|
37 | import java.util.Hashtable; |
---|
38 | import java.util.Properties; |
---|
39 | import java.util.Vector; |
---|
40 | |
---|
41 | import javax.swing.JButton; |
---|
42 | import javax.swing.JOptionPane; |
---|
43 | import javax.swing.JPanel; |
---|
44 | import javax.swing.SwingUtilities; |
---|
45 | |
---|
46 | /** |
---|
47 | * A panel for displaying the memory usage. |
---|
48 | * |
---|
49 | * @author fracpete (fracpete at waikato dot ac dot nz) |
---|
50 | * @version $Revision: 1.1 $ |
---|
51 | */ |
---|
52 | public class MemoryUsagePanel |
---|
53 | extends JPanel { |
---|
54 | |
---|
55 | /** for serialization. */ |
---|
56 | private static final long serialVersionUID = -4812319791687471721L; |
---|
57 | |
---|
58 | /** |
---|
59 | * Specialized thread for monitoring the memory usage. |
---|
60 | * |
---|
61 | * @author fracpete (fracpete at waikato dot ac dot nz) |
---|
62 | * @version $Revision: 1.1 $ |
---|
63 | */ |
---|
64 | protected class MemoryMonitor |
---|
65 | extends Thread { |
---|
66 | |
---|
67 | /** the refresh interval in msecs. */ |
---|
68 | protected int m_Interval; |
---|
69 | |
---|
70 | /** whether the thread is still running. */ |
---|
71 | protected boolean m_Monitoring; |
---|
72 | |
---|
73 | /** |
---|
74 | * default constructor. |
---|
75 | */ |
---|
76 | public MemoryMonitor() { |
---|
77 | super(); |
---|
78 | |
---|
79 | setInterval(1000); // TODO: via props file |
---|
80 | } |
---|
81 | |
---|
82 | /** |
---|
83 | * Returns the refresh interval in msecs. |
---|
84 | * |
---|
85 | * @return returns the refresh interval |
---|
86 | */ |
---|
87 | public int getInterval() { |
---|
88 | return m_Interval; |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | * Sets the refresh interval in msecs. |
---|
93 | * |
---|
94 | * @param value the refresh interval |
---|
95 | */ |
---|
96 | public void setInterval(int value) { |
---|
97 | m_Interval = value; |
---|
98 | } |
---|
99 | |
---|
100 | /** |
---|
101 | * Returns whether the thread is still running. |
---|
102 | * |
---|
103 | * @return true if the thread is still running |
---|
104 | */ |
---|
105 | public boolean isMonitoring() { |
---|
106 | return m_Monitoring; |
---|
107 | } |
---|
108 | |
---|
109 | /** |
---|
110 | * stops the monitoring thread. |
---|
111 | */ |
---|
112 | public void stopMonitoring() { |
---|
113 | m_Monitoring = false; |
---|
114 | } |
---|
115 | |
---|
116 | /** |
---|
117 | * The run method. |
---|
118 | */ |
---|
119 | public void run() { |
---|
120 | m_Monitoring = true; |
---|
121 | |
---|
122 | while (m_Monitoring) { |
---|
123 | try { |
---|
124 | Thread.sleep(m_Interval); |
---|
125 | |
---|
126 | // update GUI |
---|
127 | if (m_Monitoring) { |
---|
128 | Runnable doUpdate = new Runnable() { |
---|
129 | public void run() { |
---|
130 | update(); |
---|
131 | } |
---|
132 | }; |
---|
133 | SwingUtilities.invokeLater(doUpdate); |
---|
134 | } |
---|
135 | } |
---|
136 | catch(InterruptedException ex) { |
---|
137 | ex.printStackTrace(); |
---|
138 | } |
---|
139 | } |
---|
140 | } |
---|
141 | |
---|
142 | /** |
---|
143 | * Updates the GUI. |
---|
144 | */ |
---|
145 | protected void update() { |
---|
146 | double perc; |
---|
147 | Dimension size; |
---|
148 | |
---|
149 | // current usage |
---|
150 | perc = (double) m_Memory.getCurrent() / (double) m_Memory.getMax(); |
---|
151 | perc = Math.round(perc * 1000) / 10; |
---|
152 | |
---|
153 | // tool tip |
---|
154 | setToolTipText("" + perc + "% used"); |
---|
155 | |
---|
156 | // update history |
---|
157 | m_History.insertElementAt(perc, 0); |
---|
158 | size = getSize(); |
---|
159 | while (m_History.size() > size.getWidth()) |
---|
160 | m_History.remove(m_History.size() - 1); |
---|
161 | |
---|
162 | // display history |
---|
163 | repaint(); |
---|
164 | } |
---|
165 | } |
---|
166 | |
---|
167 | /** The name of the properties file. */ |
---|
168 | protected static String PROPERTY_FILE = "weka/gui/MemoryUsage.props"; |
---|
169 | |
---|
170 | /** Contains the properties. */ |
---|
171 | protected static Properties PROPERTIES; |
---|
172 | |
---|
173 | /** the memory usage over time. */ |
---|
174 | protected Vector<Double> m_History; |
---|
175 | |
---|
176 | /** for monitoring the memory usage. */ |
---|
177 | protected Memory m_Memory; |
---|
178 | |
---|
179 | /** the thread for monitoring the memory usage. */ |
---|
180 | protected MemoryMonitor m_Monitor; |
---|
181 | |
---|
182 | /** the button for running the garbage collector. */ |
---|
183 | protected JButton m_ButtonGC; |
---|
184 | |
---|
185 | /** the threshold percentages to change color. */ |
---|
186 | protected Vector<Double> m_Percentages; |
---|
187 | |
---|
188 | /** the corresponding colors for the thresholds. */ |
---|
189 | protected Hashtable<Double,Color> m_Colors; |
---|
190 | |
---|
191 | /** the default color. */ |
---|
192 | protected Color m_DefaultColor; |
---|
193 | |
---|
194 | /** the background color. */ |
---|
195 | protected Color m_BackgroundColor; |
---|
196 | |
---|
197 | /** the position for the dialog. */ |
---|
198 | protected Point m_FrameLocation; |
---|
199 | |
---|
200 | /** |
---|
201 | * Loads the configuration property file (USE_DYNAMIC is FALSE) or determines |
---|
202 | * the classes dynamically (USE_DYNAMIC is TRUE) |
---|
203 | * @see #USE_DYNAMIC |
---|
204 | * @see GenericPropertiesCreator |
---|
205 | */ |
---|
206 | static { |
---|
207 | // Allow a properties file in the current directory to override |
---|
208 | try { |
---|
209 | PROPERTIES = Utils.readProperties(PROPERTY_FILE); |
---|
210 | Enumeration keys = PROPERTIES.propertyNames(); |
---|
211 | if (!keys.hasMoreElements()) |
---|
212 | throw new Exception("Failed to read a property file for the " |
---|
213 | +"memory usage panel"); |
---|
214 | } |
---|
215 | catch (Exception ex) { |
---|
216 | JOptionPane.showMessageDialog( |
---|
217 | null, |
---|
218 | "Could not read a configuration file for the memory usage\n" |
---|
219 | +"panel. An example file is included with the Weka distribution.\n" |
---|
220 | +"This file should be named \"" + PROPERTY_FILE + "\" and\n" |
---|
221 | +"should be placed either in your user home (which is set\n" |
---|
222 | + "to \"" + System.getProperties().getProperty("user.home") + "\")\n" |
---|
223 | + "or the directory that java was started from\n", |
---|
224 | "MemoryUsagePanel", |
---|
225 | JOptionPane.ERROR_MESSAGE); |
---|
226 | } |
---|
227 | } |
---|
228 | |
---|
229 | /** |
---|
230 | * default constructor. |
---|
231 | */ |
---|
232 | public MemoryUsagePanel() { |
---|
233 | super(); |
---|
234 | |
---|
235 | // initializes members |
---|
236 | m_Memory = new Memory(); |
---|
237 | m_History = new Vector<Double>(); |
---|
238 | m_Percentages = new Vector<Double>(); |
---|
239 | m_Colors = new Hashtable<Double,Color>(); |
---|
240 | |
---|
241 | // colors and percentages |
---|
242 | m_BackgroundColor = parseColor("BackgroundColor", Color.WHITE); |
---|
243 | m_DefaultColor = parseColor("DefaultColor", Color.GREEN); |
---|
244 | String[] percs = PROPERTIES.getProperty("Percentages", "70,80,90").split(","); |
---|
245 | for (int i = 0; i < percs.length; i++) { |
---|
246 | // do we have a color associated with percentage? |
---|
247 | if (PROPERTIES.getProperty(percs[i]) != null) { |
---|
248 | double perc; |
---|
249 | Color color; |
---|
250 | |
---|
251 | // try parsing the number |
---|
252 | try { |
---|
253 | perc = Double.parseDouble(percs[i]); |
---|
254 | } |
---|
255 | catch (Exception e) { |
---|
256 | System.err.println( |
---|
257 | "MemoryUsagePanel: cannot parse percentage '" |
---|
258 | + percs[i] + "' - ignored!"); |
---|
259 | continue; |
---|
260 | } |
---|
261 | |
---|
262 | // try parsing the color |
---|
263 | color = parseColor(percs[i], null); |
---|
264 | if (color == null) |
---|
265 | continue; |
---|
266 | |
---|
267 | // store color and percentage |
---|
268 | m_Percentages.add(perc); |
---|
269 | m_Colors.put(perc, color); |
---|
270 | } |
---|
271 | else { |
---|
272 | System.err.println( |
---|
273 | "MemoryUsagePanel: cannot find color for percentage '" |
---|
274 | + percs[i] + "' - ignored!"); |
---|
275 | } |
---|
276 | } |
---|
277 | Collections.sort(m_Percentages); |
---|
278 | |
---|
279 | // layout |
---|
280 | setLayout(new BorderLayout()); |
---|
281 | |
---|
282 | JPanel panel = new JPanel(new BorderLayout()); |
---|
283 | add(panel, BorderLayout.EAST); |
---|
284 | |
---|
285 | m_ButtonGC = new JButton("GC"); |
---|
286 | m_ButtonGC.setToolTipText("Runs the garbage collector."); |
---|
287 | m_ButtonGC.addActionListener(new ActionListener() { |
---|
288 | public void actionPerformed(ActionEvent evt) { |
---|
289 | System.gc(); |
---|
290 | } |
---|
291 | }); |
---|
292 | panel.add(m_ButtonGC, BorderLayout.NORTH); |
---|
293 | |
---|
294 | // dimensions |
---|
295 | int height; |
---|
296 | int width; |
---|
297 | try { |
---|
298 | height = Integer.parseInt(PROPERTIES.getProperty("Height", "" + (int) m_ButtonGC.getPreferredSize().getHeight())); |
---|
299 | width = Integer.parseInt(PROPERTIES.getProperty("Width", "400")); |
---|
300 | } |
---|
301 | catch (Exception e) { |
---|
302 | System.err.println("MemoryUsagePanel: Problem parsing the dimensions - " + e); |
---|
303 | height = (int) m_ButtonGC.getPreferredSize().getHeight(); |
---|
304 | width = 400; |
---|
305 | } |
---|
306 | setPreferredSize(new Dimension(width, height)); |
---|
307 | |
---|
308 | // position |
---|
309 | int top; |
---|
310 | int left; |
---|
311 | try { |
---|
312 | top = Integer.parseInt(PROPERTIES.getProperty("Top", "0")); |
---|
313 | left = Integer.parseInt(PROPERTIES.getProperty("Left", "0")); |
---|
314 | } |
---|
315 | catch (Exception e) { |
---|
316 | System.err.println("MemoryUsagePanel: Problem parsing the position - " + e); |
---|
317 | top = 0; |
---|
318 | left = 0; |
---|
319 | } |
---|
320 | m_FrameLocation = new Point(left, top); |
---|
321 | |
---|
322 | // monitoring thread |
---|
323 | int interval; |
---|
324 | try { |
---|
325 | interval = Integer.parseInt(PROPERTIES.getProperty("Interval", "1000")); |
---|
326 | } |
---|
327 | catch (Exception e) { |
---|
328 | System.err.println("MemoryUsagePanel: Problem parsing the refresh interval - " + e); |
---|
329 | interval = 1000; |
---|
330 | } |
---|
331 | m_Monitor = new MemoryMonitor(); |
---|
332 | m_Monitor.setInterval(interval); |
---|
333 | m_Monitor.setPriority(Thread.MAX_PRIORITY); |
---|
334 | m_Monitor.start(); |
---|
335 | } |
---|
336 | |
---|
337 | /** |
---|
338 | * parses the color and returns the corresponding Color object. |
---|
339 | * |
---|
340 | * @param prop the color property to read and parse |
---|
341 | * @param defValue the default color |
---|
342 | * @return the parsed color or the default color of the |
---|
343 | */ |
---|
344 | protected Color parseColor(String prop, Color defValue) { |
---|
345 | Color result; |
---|
346 | Color color; |
---|
347 | String colorStr; |
---|
348 | |
---|
349 | result = defValue; |
---|
350 | |
---|
351 | try { |
---|
352 | colorStr = PROPERTIES.getProperty(prop); |
---|
353 | color = VisualizeUtils.processColour(colorStr, result); |
---|
354 | if (color == null) |
---|
355 | throw new Exception(colorStr); |
---|
356 | result = color; |
---|
357 | } |
---|
358 | catch (Exception e) { |
---|
359 | System.err.println( |
---|
360 | "MemoryUsagePanel: cannot parse color '" |
---|
361 | + e.getMessage() + "' - ignored!"); |
---|
362 | } |
---|
363 | |
---|
364 | return result; |
---|
365 | } |
---|
366 | |
---|
367 | /** |
---|
368 | * Returns whether the thread is still running. |
---|
369 | * |
---|
370 | * @return true if the thread is still running |
---|
371 | */ |
---|
372 | public boolean isMonitoring() { |
---|
373 | return m_Monitor.isMonitoring(); |
---|
374 | } |
---|
375 | |
---|
376 | /** |
---|
377 | * stops the monitoring thread. |
---|
378 | */ |
---|
379 | public void stopMonitoring() { |
---|
380 | m_Monitor.stopMonitoring(); |
---|
381 | } |
---|
382 | |
---|
383 | /** |
---|
384 | * Returns the default position for the dialog. |
---|
385 | * |
---|
386 | * @return the default position |
---|
387 | */ |
---|
388 | public Point getFrameLocation() { |
---|
389 | return m_FrameLocation; |
---|
390 | } |
---|
391 | |
---|
392 | /** |
---|
393 | * draws the background image. |
---|
394 | * |
---|
395 | * @param g the graphics context |
---|
396 | */ |
---|
397 | public void paintComponent(Graphics g) { |
---|
398 | int i; |
---|
399 | int n; |
---|
400 | int len; |
---|
401 | double scale; |
---|
402 | double perc; |
---|
403 | Color color; |
---|
404 | |
---|
405 | super.paintComponent(g); |
---|
406 | |
---|
407 | g.setColor(m_BackgroundColor); |
---|
408 | g.fillRect(0, 0, getWidth(), getHeight()); |
---|
409 | scale = (double) getHeight() / 100.0; |
---|
410 | for (i = 0; i < m_History.size(); i++) { |
---|
411 | perc = m_History.get(i); |
---|
412 | |
---|
413 | // determine color |
---|
414 | color = m_DefaultColor; |
---|
415 | for (n = m_Percentages.size() - 1; n >= 0; n--) { |
---|
416 | if (perc >= m_Percentages.get(n)) { |
---|
417 | color = m_Colors.get(m_Percentages.get(n)); |
---|
418 | break; |
---|
419 | } |
---|
420 | } |
---|
421 | |
---|
422 | // paint line |
---|
423 | g.setColor(color); |
---|
424 | len = (int) Math.round(perc * scale); |
---|
425 | g.drawLine(i, getHeight() - 1, i, getHeight() - len); |
---|
426 | } |
---|
427 | } |
---|
428 | } |
---|