Mercurial > hg > release > thermostat-0.15
changeset 260:e5ca1ae73748
PR959: Show exact memory sizes in the JVM's memory tab
Reviewed-by: rkennke
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-April/001045.html
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Mon, 23 Apr 2012 16:24:41 -0400 |
parents | 04338ff62c91 |
children | 0ad7fdcad47e |
files | client/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java client/src/main/java/com/redhat/thermostat/client/ui/IconResource.java client/src/main/java/com/redhat/thermostat/client/ui/MemorySpacePanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryPanel.java client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryView.java client/src/main/resources/com/redhat/thermostat/client/locale/strings.properties client/src/test/java/com/redhat/thermostat/client/ui/VmMemoryControllerTest.java |
diffstat | 8 files changed, 392 insertions(+), 79 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java Mon Apr 23 16:56:10 2012 +0200 +++ b/client/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java Mon Apr 23 16:24:41 2012 -0400 @@ -61,7 +61,7 @@ MENU_EDIT_ENABLE_HISTORY_MODE, MENU_HELP, MENU_HELP_ABOUT, - + GARBAGE_COLLECTION, YOUNG_GEN, EDEN_GEN, @@ -164,11 +164,10 @@ VM_CPU_CHART_LOAD_LABEL, VM_CPU_CHART_TIME_LABEL, - VM_CURRENT_MEMORY_CHART_USED, - VM_CURRENT_MEMORY_CHART_CAPACITY, - VM_CURRENT_MEMORY_CHART_MAX_CAPACITY, - VM_CURRENT_MEMORY_CHART_SPACE, - VM_CURRENT_MEMORY_CHART_SIZE, + VM_MEMORY_SPACE_TITLE, + VM_MEMORY_SPACE_USED, + VM_MEMORY_SPACE_FREE, + VM_MEMORY_SPACE_ADDITIONAL, VM_GC_COLLECTOR_OVER_GENERATION, VM_GC_COLLECTOR_CHART_REAL_TIME_LABEL,
--- a/client/src/main/java/com/redhat/thermostat/client/ui/IconResource.java Mon Apr 23 16:56:10 2012 +0200 +++ b/client/src/main/java/com/redhat/thermostat/client/ui/IconResource.java Mon Apr 23 16:24:41 2012 -0400 @@ -58,6 +58,8 @@ public static final IconResource NETWORK_SERVER = new IconResource(ICON_PREFIX + "48x48/places/network-server.png"); public static final IconResource NETWORK_GROUP = new IconResource(ICON_PREFIX + "48x48/places/network-workgroup.png"); + public static final IconResource ARROW_RIGHT = new IconResource(ICON_PREFIX + "48x48/actions/go-next.png"); + public static final IconResource SEARCH = new IconResource(ICON_PREFIX + "16x16/actions/search.png"); private final String path;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/main/java/com/redhat/thermostat/client/ui/MemorySpacePanel.java Mon Apr 23 16:24:41 2012 -0400 @@ -0,0 +1,109 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.ui; + +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.LayoutStyle.ComponentPlacement; + +public class MemorySpacePanel extends JPanel { + + private final JProgressBar percentagePanel; + private final JLabel additionalDetailsIcon; + private final JLabel lblUsed; + private final JLabel lblAvailable; + + public MemorySpacePanel(String regionName) { + JLabel lblRegionName = new JLabel(regionName); + + percentagePanel = new JProgressBar(0, 100); + + additionalDetailsIcon = new JLabel(IconResource.ARROW_RIGHT.getIcon()); + + lblUsed = new JLabel("${USED}"); + lblAvailable = new JLabel("${AVAILABLE}"); + + GroupLayout groupLayout = new GroupLayout(this); + groupLayout.setHorizontalGroup( + groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addContainerGap() + .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) + .addComponent(lblRegionName) + .addGroup(groupLayout.createSequentialGroup() + .addGap(12) + .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) + .addComponent(percentagePanel, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE) + .addGroup(groupLayout.createSequentialGroup() + .addComponent(lblUsed) + .addPreferredGap(ComponentPlacement.RELATED, 441, Short.MAX_VALUE) + .addComponent(lblAvailable))))) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(additionalDetailsIcon) + .addContainerGap()) + ); + groupLayout.setVerticalGroup( + groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblRegionName) + .addPreferredGap(ComponentPlacement.RELATED) + .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) + .addComponent(additionalDetailsIcon, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(percentagePanel, GroupLayout.DEFAULT_SIZE, 44, Short.MAX_VALUE)) + .addPreferredGap(ComponentPlacement.RELATED) + .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE) + .addComponent(lblUsed) + .addComponent(lblAvailable)) + .addGap(5)) + ); + setLayout(groupLayout); + } + + + public void updateRegionData(int percentageUsed, String currentlyUsed, String currentlyAvailable, String allocatable) { + percentagePanel.setValue(percentageUsed); + + lblUsed.setText(currentlyUsed); + lblAvailable.setText(currentlyAvailable); + additionalDetailsIcon.setToolTipText(allocatable); + } + +}
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java Mon Apr 23 16:56:10 2012 +0200 +++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryController.java Mon Apr 23 16:24:41 2012 -0400 @@ -36,13 +36,17 @@ package com.redhat.thermostat.client.ui; +import static com.redhat.thermostat.client.locale.Translate.localize; + import java.awt.Component; +import java.util.ArrayList; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.TimeUnit; import com.redhat.thermostat.client.AsyncUiFacade; +import com.redhat.thermostat.client.locale.LocaleResources; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.common.appctx.ApplicationContext; import com.redhat.thermostat.common.dao.VmMemoryStatDAO; import com.redhat.thermostat.common.dao.VmRef; @@ -52,21 +56,19 @@ class VmMemoryController implements AsyncUiFacade { - private final VmRef ref; private final VmMemoryView view; private final VmMemoryStatDAO dao; - private final Timer timer = new Timer(); + private final Timer timer; + + private final List<String> spacesInView = new ArrayList<>(); - public VmMemoryController(VmRef ref) { - this.ref = ref; + public VmMemoryController(final VmRef ref) { dao = ApplicationContext.getInstance().getDAOFactory().getVmMemoryStatDAO(); + timer = ApplicationContext.getInstance().getTimerFactory().createTimer(); view = ApplicationContext.getInstance().getViewFactory().getView(VmMemoryView.class); - } - @Override - public void start() { - timer.scheduleAtFixedRate(new TimerTask() { + timer.setAction(new Runnable() { @Override public void run() { VmMemoryStat info = dao.getLatestMemoryStat(ref); @@ -74,18 +76,37 @@ for (Generation generation: generations) { List<Space> spaces = generation.spaces; for (Space space: spaces) { - view.setMemoryRegionSize(space.name, space.used, space.capacity, space.maxCapacity); + + if (!spacesInView.contains(space.name)) { + view.addRegion(space.name); + spacesInView.add(space.name); + } + + int percentageUsed = (int) (100.0 * space.used/space.capacity); + String currentlyUsed = localize(LocaleResources.VM_MEMORY_SPACE_USED, String.valueOf(space.used)); + String currentlyUnused = localize(LocaleResources.VM_MEMORY_SPACE_FREE, String.valueOf(space.capacity - space.used)); + String allocatable = localize(LocaleResources.VM_MEMORY_SPACE_ADDITIONAL, String.valueOf(space.maxCapacity-space.capacity)); + String name = space.name; // FIXME + view.updateRegionSize(name, percentageUsed, currentlyUsed, currentlyUnused, allocatable); + } } + } + }); + timer.setInitialDelay(0); + timer.setDelay(10); + timer.setTimeUnit(TimeUnit.MILLISECONDS); + timer.setSchedulingType(SchedulingType.FIXED_RATE); + } - } - - }, 0, TimeUnit.SECONDS.toMillis(5)); + @Override + public void start() { + timer.start(); } @Override public void stop() { - timer.cancel(); + timer.stop(); } public Component getComponent() {
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryPanel.java Mon Apr 23 16:56:10 2012 +0200 +++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryPanel.java Mon Apr 23 16:24:41 2012 -0400 @@ -37,18 +37,17 @@ package com.redhat.thermostat.client.ui; import static com.redhat.thermostat.client.locale.Translate.localize; +import java.awt.Component; +import java.util.HashMap; +import java.util.Map; -import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; - +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JLabel; import javax.swing.JPanel; - -import org.jfree.chart.ChartFactory; -import org.jfree.chart.ChartPanel; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.data.category.DefaultCategoryDataset; +import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.BoxLayout; +import javax.swing.SwingUtilities; import com.redhat.thermostat.client.locale.LocaleResources; @@ -56,58 +55,77 @@ private static final long serialVersionUID = -2882890932814218436L; - private final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + private final Map<String, MemorySpacePanel> regions = new HashMap<>(); + + private final JPanel currentRegionSizePanel; public VmMemoryPanel() { - initializePanel(); + JLabel lblMem = new JLabel(localize(LocaleResources.VM_MEMORY_SPACE_TITLE)); + + currentRegionSizePanel = new JPanel(); + + GroupLayout groupLayout = new GroupLayout(this); + groupLayout.setHorizontalGroup( + groupLayout.createParallelGroup(Alignment.TRAILING) + .addGroup(groupLayout.createSequentialGroup() + .addContainerGap() + .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addComponent(currentRegionSizePanel, GroupLayout.DEFAULT_SIZE, 630, Short.MAX_VALUE) + .addContainerGap()) + .addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup() + .addComponent(lblMem) + .addGap(491)))) + ); + groupLayout.setVerticalGroup( + groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblMem) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(currentRegionSizePanel, GroupLayout.DEFAULT_SIZE, 483, Short.MAX_VALUE) + .addContainerGap()) + ); + currentRegionSizePanel.setLayout(new BoxLayout(currentRegionSizePanel, BoxLayout.PAGE_AXIS)); + setLayout(groupLayout); + } @Override - public void setMemoryRegionSize(String name, long used, long allocated, long max) { - dataset.addValue(used, localize(LocaleResources.VM_CURRENT_MEMORY_CHART_USED), name); - dataset.addValue(allocated - used, - localize(LocaleResources.VM_CURRENT_MEMORY_CHART_CAPACITY), name); - dataset.addValue(max - allocated, - localize(LocaleResources.VM_CURRENT_MEMORY_CHART_MAX_CAPACITY), name); - } - - private void initializePanel() { - JPanel panel = this; - panel.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = 0; - c.fill = GridBagConstraints.BOTH; - c.weightx = 1; - c.weighty = 1; - panel.add(createCurrentMemoryDisplay(), c); - c.gridy++; - panel.add(createMemoryHistoryPanel(), c); + public void addRegion(final String humanReadableName) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + MemorySpacePanel regionInfo = new MemorySpacePanel(humanReadableName); + regions.put(humanReadableName, regionInfo); + currentRegionSizePanel.add(regionInfo); + currentRegionSizePanel.revalidate(); + } + }); } - private Component createCurrentMemoryDisplay() { - JFreeChart chart = ChartFactory.createStackedBarChart( - null, - localize(LocaleResources.VM_CURRENT_MEMORY_CHART_SPACE), - localize(LocaleResources.VM_CURRENT_MEMORY_CHART_SIZE), - dataset, - PlotOrientation.HORIZONTAL, true, false, false); - - ChartPanel chartPanel = new ChartPanel(chart); - // make this chart non-interactive - chartPanel.setDisplayToolTips(true); - chartPanel.setDoubleBuffered(true); - chartPanel.setMouseZoomable(false); - chartPanel.setPopupMenu(null); - - return chartPanel; + @Override + public void removeAllRegions() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + regions.clear(); + currentRegionSizePanel.removeAll(); + currentRegionSizePanel.revalidate(); + } + }); } - private Component createMemoryHistoryPanel() { - JPanel historyPanel = new JPanel(); - // TODO implement this - return historyPanel; + @Override + public void updateRegionSize(final String name, final int percentageUsed, final String currentlyUsed, final String currentlyAvailable, final String allocatable) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + regions.get(name).updateRegionData(percentageUsed, currentlyUsed, currentlyAvailable, allocatable); + } + }); + } @Override
--- a/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryView.java Mon Apr 23 16:56:10 2012 +0200 +++ b/client/src/main/java/com/redhat/thermostat/client/ui/VmMemoryView.java Mon Apr 23 16:24:41 2012 -0400 @@ -42,7 +42,11 @@ public interface VmMemoryView extends View { - void setMemoryRegionSize(String name, long used, long allocated, long max); + void addRegion(String humanReadableName); + + void removeAllRegions(); + + void updateRegionSize(String name, int percentageUsed, String currentlyUsed, String currentlyAvailable, String allocatable); Component getUiComponent();
--- a/client/src/main/resources/com/redhat/thermostat/client/locale/strings.properties Mon Apr 23 16:56:10 2012 +0200 +++ b/client/src/main/resources/com/redhat/thermostat/client/locale/strings.properties Mon Apr 23 16:24:41 2012 -0400 @@ -125,11 +125,10 @@ VM_CPU_CHART_LOAD_LABEL = % CPU VM_CPU_CHART_TIME_LABEL = Time -VM_CURRENT_MEMORY_CHART_USED = Used -VM_CURRENT_MEMORY_CHART_CAPACITY = Capacity -VM_CURRENT_MEMORY_CHART_MAX_CAPACITY = Max Capacity -VM_CURRENT_MEMORY_CHART_SPACE = Memory Region -VM_CURRENT_MEMORY_CHART_SIZE = Size +VM_MEMORY_SPACE_TITLE = Memory Region Sizes +VM_MEMORY_SPACE_USED = {0} bytes used +VM_MEMORY_SPACE_FREE = {0} bytes unused +VM_MEMORY_SPACE_ADDITIONAL = An additional {0} bytes can be allocated VM_GC_COLLECTOR_OVER_GENERATION = Collector {0} running on {1} VM_GC_COLLECTOR_CHART_REAL_TIME_LABEL = Time
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/test/java/com/redhat/thermostat/client/ui/VmMemoryControllerTest.java Mon Apr 23 16:24:41 2012 -0400 @@ -0,0 +1,161 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.ui; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.ViewFactory; +import com.redhat.thermostat.common.appctx.ApplicationContext; +import com.redhat.thermostat.common.appctx.ApplicationContextUtil; +import com.redhat.thermostat.common.dao.DAOFactory; +import com.redhat.thermostat.common.dao.VmMemoryStatDAO; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.model.VmMemoryStat; +import com.redhat.thermostat.common.model.VmMemoryStat.Generation; +import com.redhat.thermostat.common.model.VmMemoryStat.Space; + +public class VmMemoryControllerTest { + + private final long TIMESTAMP = 1; + private final int VM_ID = 99; + + private List<Generation> generations = new ArrayList<>(); + + private Timer timer; + private Space space; + private Generation gen; + private VmMemoryController controller; + private VmMemoryView view; + private Runnable timerAction; + + + @Before() + public void setUp() { + ApplicationContextUtil.resetApplicationContext(); + + // Setup timer. + timer = mock(Timer.class); + ArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(actionCaptor.capture()); + + TimerFactory timerFactory = mock(TimerFactory.class); + when(timerFactory.createTimer()).thenReturn(timer); + ApplicationContext.getInstance().setTimerFactory(timerFactory); + + space = new Space(); + space.name = "space"; + space.index = 0; + space.used = 10; + space.capacity = 100; + space.maxCapacity = 1000; + + gen = new Generation(); + gen.spaces = new ArrayList<>(); + gen.spaces.add(space); + + generations.add(gen); + + // Setup dao + VmMemoryStat vmMemory = new VmMemoryStat(TIMESTAMP, VM_ID, generations); + VmMemoryStatDAO memoryStatDao = mock(VmMemoryStatDAO.class); + when(memoryStatDao.getLatestMemoryStat(any(VmRef.class))).thenReturn(vmMemory); + + DAOFactory daoFactory = mock(DAOFactory.class); + when(daoFactory.getVmMemoryStatDAO()).thenReturn(memoryStatDao); + + ApplicationContext.getInstance().setDAOFactory(daoFactory); + + // Setup view + view = mock(VmMemoryView.class); + ViewFactory viewFactory = mock(ViewFactory.class); + when(viewFactory.getView(eq(VmMemoryView.class))).thenReturn(view); + ApplicationContext.getInstance().setViewFactory(viewFactory); + + + VmRef ref = mock(VmRef.class); + + controller = new VmMemoryController(ref); + timerAction = actionCaptor.getValue(); + + } + + @After + public void tearDown() { + ApplicationContextUtil.resetApplicationContext(); + } + + @Test + public void testTimer() { + + controller.start(); + + verify(timer).start(); + verify(timer).setSchedulingType(SchedulingType.FIXED_RATE); + + controller.stop(); + + verify(timer).stop(); + } + + + @Test + public void testControllerUpdatesView() { + + timerAction.run(); + + verify(view).addRegion(eq("space")); + verify(view).updateRegionSize(eq("space"), eq(10), contains("10"), contains("90"), contains("900")); + } +}