Mercurial > hg > release > thermostat-1.6
changeset 1948:131195abd5fc
Add additional class statistics.
Backport includes two patches from HEAD in one commit.
http://icedtea.classpath.org/hg/thermostat/rev/bf3bb0a9f9fa : Add additional class statistics
http://icedtea.classpath.org/hg/thermostat/rev/746fd0b71d73 : Fix test
PR3034
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-June/019863.html
line wrap: on
line diff
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Fri Jun 24 12:17:11 2016 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Mon Jun 27 12:24:03 2016 -0400 @@ -668,8 +668,12 @@ // manually for this test. String strDesc = "ADD vm-class-stats SET 'agentId' = ?s , " + "'vmId' = ?s , " + - "'timeStamp' = ?l , " + - "'loadedClasses' = ?l"; + "'timeStamp' = ?l , " + + "'loadedClasses' = ?l , " + + "'loadedBytes' = ?l , " + + "'unloadedClasses' = ?l , " + + "'unloadedBytes' = ?l , " + + "'classLoadTime' = ?l"; StatementDescriptor<VmClassStat> desc = new StatementDescriptor<>(VmClassStatDAO.vmClassStatsCategory, strDesc); VmClassStat pojo = new VmClassStat(); pojo.setAgentId("fluff"); @@ -705,6 +709,10 @@ add.setString(1, pojo.getVmId()); add.setLong(2, pojo.getTimeStamp()); add.setLong(3, pojo.getLoadedClasses()); + add.setLong(4, pojo.getLoadedBytes()); + add.setLong(5, pojo.getUnloadedClasses()); + add.setLong(6, pojo.getUnloadedBytes()); + add.setLong(7, pojo.getClassLoadTime()); add.execute(); }
--- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractor.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatDataExtractor.java Mon Jun 27 12:24:03 2016 -0400 @@ -59,6 +59,8 @@ * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern() */ + // For the definitions of the values, see VmClassStat. + private final VmUpdate update; public VmClassStatDataExtractor(VmUpdate update) { @@ -66,8 +68,28 @@ } public Long getLoadedClasses() throws VmUpdateException { - return update.getPerformanceCounterLong("java.cls.loadedClasses"); + return update.getPerformanceCounterLong("java.cls.loadedClasses") + + update.getPerformanceCounterLong("java.cls.sharedLoadedClasses"); + } + + public Long getLoadedBytes() throws VmUpdateException { + return update.getPerformanceCounterLong("sun.cls.loadedBytes") + + update.getPerformanceCounterLong("sun.cls.sharedLoadedBytes"); + } + + public Long getUnloadedClasses() throws VmUpdateException { + return update.getPerformanceCounterLong("java.cls.unloadedClasses") + + update.getPerformanceCounterLong("java.cls.sharedUnloadedClasses"); + } + + public Long getUnloadedBytes() throws VmUpdateException { + return update.getPerformanceCounterLong("sun.cls.unloadedBytes") + + update.getPerformanceCounterLong("sun.cls.sharedUnloadedBytes"); + } + + public Long getClassLoadTime() throws VmUpdateException { + return update.getPerformanceCounterLong("sun.cls.time") + / update.getPerformanceCounterLong("sun.os.hrt.frequency"); } } -
--- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListener.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListener.java Mon Jun 27 12:24:03 2016 -0400 @@ -66,21 +66,32 @@ public void countersUpdated(VmUpdate update) { VmClassStatDataExtractor extractor = new VmClassStatDataExtractor(update); try { - Long loadedClasses = extractor.getLoadedClasses(); - if (loadedClasses != null) { - long timestamp = System.currentTimeMillis(); - VmClassStat stat = new VmClassStat(writerId, vmId, timestamp, loadedClasses); - dao.putVmClassStat(stat); - } - else { - logWarningOnce("Unable to determine number of loaded classes for VM " - + vmId); - } + long loadedClasses = valueOrUnknown(extractor.getLoadedClasses(), "number of loaded classes", vmId); + long loadedBytes = valueOrUnknown(extractor.getLoadedBytes(), "number of loaded bytes", vmId); + long unloadedClasses = valueOrUnknown(extractor.getUnloadedClasses(), "number of unloaded", vmId); + long unloadedBytes = valueOrUnknown(extractor.getUnloadedBytes(), "number of unloaded bytes", vmId); + long classLoadTime = valueOrUnknown(extractor.getClassLoadTime(), "class load time", vmId); + + long timestamp = System.currentTimeMillis(); + VmClassStat stat = new VmClassStat(writerId, vmId, timestamp, + loadedClasses, loadedBytes, + unloadedClasses, unloadedBytes, + classLoadTime); + + dao.putVmClassStat(stat); + } catch (VmUpdateException e) { logger.log(Level.WARNING, "Error gathering class info for VM " + vmId, e); } } - + + private long valueOrUnknown(Long value, String valudDescription, String vmId) { + if (value == null) { + logWarningOnce("Unable to determine " + valudDescription + " for VM " + vmId); + } + return value == null ? VmClassStat.UNKNOWN : value; + } + private void logWarningOnce(String message) { if (!error) { logger.log(Level.WARNING, message);
--- a/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListenerTest.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/agent/src/test/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatVmListenerTest.java Mon Jun 27 12:24:03 2016 -0400 @@ -58,22 +58,51 @@ public class VmClassStatVmListenerTest { private static final String VM_ID = "vmId"; - private static final Long LOADED_CLASSES = 1234L; + private static final Long LOADED_CLASSES_NON_SHARED = 1234L; + private static final Long LOADED_CLASSES_SHARED = 1234L; + private static final Long LOADED_CLASSES = LOADED_CLASSES_NON_SHARED + LOADED_CLASSES_SHARED; + private static final Long LOADED_BYTES_NON_SHARED = 1234L; + private static final Long LOADED_BYTES_SHARED = 1234L; + private static final Long LOADED_BYTES = LOADED_BYTES_NON_SHARED + LOADED_BYTES_SHARED; + private static final Long UNLOADED_CLASSES_NON_SHARED = 1234L; + private static final Long UNLOADED_CLASSES_SHARED = 1234L; + private static final Long UNLOADED_CLASSES = UNLOADED_CLASSES_NON_SHARED + UNLOADED_CLASSES_SHARED; + private static final Long UNLOADED_BYTES_NON_SHARED = 1234L; + private static final Long UNLOADED_BYTES_SHARED = 1234L; + private static final Long UNLOADED_BYTES = UNLOADED_BYTES_NON_SHARED + UNLOADED_BYTES_SHARED; + private static final Long CLASS_TIME_TICKS = 4242L; + private static final Long FREQUENCY = 2L; + private static final Long CLASS_TIME = CLASS_TIME_TICKS / FREQUENCY; private VmClassStatDAO dao; private VmClassStatVmListener listener; + private VmUpdate update; + @Before - public void setUp() { + public void setUp() throws VmUpdateException { dao = mock(VmClassStatDAO.class); listener = new VmClassStatVmListener("foo-agent", dao, VM_ID); + + update = mock(VmUpdate.class); + when(update.getPerformanceCounterLong("java.cls.loadedClasses")).thenReturn(LOADED_CLASSES_NON_SHARED); + when(update.getPerformanceCounterLong("java.cls.sharedLoadedClasses")).thenReturn(LOADED_CLASSES_SHARED); + + when(update.getPerformanceCounterLong("sun.cls.loadedBytes")).thenReturn(LOADED_BYTES_NON_SHARED); + when(update.getPerformanceCounterLong("sun.cls.sharedLoadedBytes")).thenReturn(LOADED_BYTES_SHARED); + + when(update.getPerformanceCounterLong("java.cls.unloadedClasses")).thenReturn(UNLOADED_CLASSES_NON_SHARED); + when(update.getPerformanceCounterLong("java.cls.sharedUnloadedClasses")).thenReturn(UNLOADED_CLASSES_SHARED); + + when(update.getPerformanceCounterLong("sun.cls.unloadedBytes")).thenReturn(UNLOADED_BYTES_NON_SHARED); + when(update.getPerformanceCounterLong("sun.cls.sharedUnloadedBytes")).thenReturn(UNLOADED_BYTES_SHARED); + + when(update.getPerformanceCounterLong("sun.cls.time")).thenReturn(CLASS_TIME_TICKS); + when(update.getPerformanceCounterLong("sun.os.hrt.frequency")).thenReturn(FREQUENCY); } @Test public void testMonitorUpdatedClassStat() throws Exception { - VmUpdate update = mock(VmUpdate.class); - when(update.getPerformanceCounterLong(eq("java.cls.loadedClasses"))).thenReturn(LOADED_CLASSES); - listener.countersUpdated(update); ArgumentCaptor<VmClassStat> arg = ArgumentCaptor.forClass(VmClassStat.class); @@ -85,9 +114,6 @@ @Test public void testMonitorUpdatedClassStatTwice() throws Exception { - VmUpdate update = mock(VmUpdate.class); - when(update.getPerformanceCounterLong(eq("java.cls.loadedClasses"))).thenReturn(LOADED_CLASSES); - listener.countersUpdated(update); listener.countersUpdated(update); @@ -97,21 +123,11 @@ @Test public void testMonitorUpdateFails() throws VmUpdateException { - VmUpdate update = mock(VmUpdate.class); when(update.getPerformanceCounterLong(anyString())).thenThrow(new VmUpdateException()); listener.countersUpdated(update); verifyNoMoreInteractions(dao); } - - @Test - public void testMonitorUpdatedClassStatNoCounter() throws Exception { - VmUpdate update = mock(VmUpdate.class); - when(update.getPerformanceCounterLong(eq("java.cls.loadedClasses"))).thenReturn(null); - listener.countersUpdated(update); - - verify(dao, never()).putVmClassStat(any(VmClassStat.class)); - } }
--- a/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatView.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatView.java Mon Jun 27 12:24:03 2016 -0400 @@ -37,34 +37,37 @@ package com.redhat.thermostat.vm.classstat.client.core; import java.util.List; -import java.util.concurrent.TimeUnit; +import com.redhat.thermostat.client.core.experimental.Duration; import com.redhat.thermostat.client.core.views.BasicView; import com.redhat.thermostat.client.core.views.UIComponent; -import com.redhat.thermostat.client.core.experimental.Duration; -import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.storage.model.DiscreteTimeData; public abstract class VmClassStatView extends BasicView implements UIComponent { - public enum UserAction { - USER_CHANGED_TIME_RANGE, + public enum Group { + NUMBER, + SIZE, + ; } - public abstract void addUserActionListener(ActionListener<UserAction> listener); - - public abstract void removeUserActionListener(ActionListener<UserAction> listener); + public static final String TAG_LOADED_CLASSES = "loadedClasses"; + public static final String TAG_LOADED_BYTES = "loadedBytes"; + public static final String TAG_UNLOADED_CLASSES = "unloadedClasses"; + public static final String TAG_UNLOADED_BYTES = "unloadedBytes"; + public static final String TAG_CLASS_LOAD_TIME= "classLoadTime"; public abstract Duration getUserDesiredDuration(); - public abstract void setVisibleDataRange(int time, TimeUnit unit); - public abstract void setAvailableDataRange(Range<Long> availableDataRange); - public abstract void clearClassCount(); + public abstract void addClassChart(Group group, String tag, LocalizedString name); + public abstract void removeClassChart(Group group, String tag); - public abstract void addClassCount(List<DiscreteTimeData<Long>> data); + public abstract void addClassData(String tag, List<DiscreteTimeData<? extends Number>> data); + public abstract void clearMemoryData(String tag); }
--- a/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatController.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatController.java Mon Jun 27 12:24:03 2016 -0400 @@ -36,19 +36,22 @@ package com.redhat.thermostat.vm.classstat.client.core.internal; -import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; + import com.redhat.thermostat.client.core.controllers.InformationServiceController; -import com.redhat.thermostat.client.core.views.UIComponent; -import com.redhat.thermostat.client.core.views.BasicView.Action; import com.redhat.thermostat.client.core.experimental.Duration; import com.redhat.thermostat.client.core.experimental.TimeRangeController; +import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.client.core.views.UIComponent; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ApplicationService; import com.redhat.thermostat.common.NotImplementedException; +import com.redhat.thermostat.common.Size; +import com.redhat.thermostat.common.Size.Unit; import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.common.model.Range; @@ -71,11 +74,14 @@ private class UpdateChartData implements Runnable { @Override public void run() { - final List<DiscreteTimeData<Long>> data = new ArrayList<>(); - VmClassStat oldest = dao.getOldest(ref); VmClassStat newest = dao.getNewest(ref); + final List<DiscreteTimeData<? extends Number>> loadedClasses = new LinkedList<>(); + final List<DiscreteTimeData<? extends Number>> loadedBytes = new LinkedList<>(); + final List<DiscreteTimeData<? extends Number>> unloadedClasses = new LinkedList<>(); + final List<DiscreteTimeData<? extends Number>> unloadedBytes = new LinkedList<>(); + Range<Long> newAvailableRange = new Range<>(oldest.getTimeStamp(), newest.getTimeStamp()); TimeRangeController.StatsSupplier<VmClassStat, VmRef> singleValueSupplier = new TimeRangeController.StatsSupplier<VmClassStat, VmRef>() { @@ -87,15 +93,27 @@ TimeRangeController.SingleArgRunnable<VmClassStat> runnable = new TimeRangeController.SingleArgRunnable<VmClassStat>() { @Override - public void run(VmClassStat arg) { - data.add(new DiscreteTimeData<>(arg.getTimeStamp(), arg.getLoadedClasses())); + public void run(VmClassStat stat) { + long timeStamp = stat.getTimeStamp(); + + loadedClasses.add(new DiscreteTimeData<Number>(timeStamp, stat.getLoadedClasses())); + loadedBytes.add(new DiscreteTimeData<Number>(timeStamp, bytesToMegaBytes(stat.getLoadedBytes()))); + unloadedClasses.add(new DiscreteTimeData<Number>(timeStamp, stat.getUnloadedClasses())); + unloadedBytes.add(new DiscreteTimeData<Number>(timeStamp, bytesToMegaBytes(stat.getUnloadedBytes()))); + } + + private long bytesToMegaBytes(long bytes) { + return (long) Size.bytes(bytes).convertTo(Unit.MiB).getValue(); } }; timeRangeController.update(userDesiredDuration, newAvailableRange, singleValueSupplier, ref, runnable); classesView.setAvailableDataRange(timeRangeController.getAvailableRange()); - classesView.addClassCount(data); + classesView.addClassData(VmClassStatView.TAG_LOADED_CLASSES, loadedClasses); + classesView.addClassData(VmClassStatView.TAG_LOADED_BYTES, loadedBytes); + classesView.addClassData(VmClassStatView.TAG_UNLOADED_CLASSES, unloadedClasses); + classesView.addClassData(VmClassStatView.TAG_UNLOADED_BYTES, unloadedBytes); } } @@ -118,6 +136,14 @@ timer.setInitialDelay(0); classesView = viewProvider.createView(); + classesView.addClassChart(VmClassStatView.Group.NUMBER, VmClassStatView.TAG_LOADED_CLASSES, + translator.localize(LocaleResources.VM_CLASSES_CHART_LOADED_CLASSES_LENGEND)); + classesView.addClassChart(VmClassStatView.Group.SIZE, VmClassStatView.TAG_LOADED_BYTES, + translator.localize(LocaleResources.VM_CLASSES_CHART_LOADED_BYTES_LENGEND)); + classesView.addClassChart(VmClassStatView.Group.NUMBER, VmClassStatView.TAG_UNLOADED_CLASSES, + translator.localize(LocaleResources.VM_CLASSES_CHART_UNLOADED_CLASSES_LENGEND)); + classesView.addClassChart(VmClassStatView.Group.SIZE, VmClassStatView.TAG_UNLOADED_BYTES, + translator.localize(LocaleResources.VM_CLASSES_CHART_UNLOADED_BYTES_LENGEND)); classesView.addActionListener(new ActionListener<VmClassStatView.Action>() { @Override @@ -135,22 +161,6 @@ } }); - classesView.addUserActionListener(new ActionListener<VmClassStatView.UserAction>() { - - @Override - public void actionPerformed(final ActionEvent<VmClassStatView.UserAction> actionEvent) { - switch (actionEvent.getActionId()) { - case USER_CHANGED_TIME_RANGE: - Duration duration = classesView.getUserDesiredDuration(); - userDesiredDuration = duration; - classesView.setVisibleDataRange(duration.value, duration.unit); - break; - default: - throw new AssertionError("Unhandled action type"); - } - } - }); - userDesiredDuration = classesView.getUserDesiredDuration(); timeRangeController = new TimeRangeController<>();
--- a/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/locale/LocaleResources.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/locale/LocaleResources.java Mon Jun 27 12:24:03 2016 -0400 @@ -40,10 +40,17 @@ public enum LocaleResources { - VM_LOADED_CLASSES, - VM_CLASSES_CHART_REAL_TIME_LABEL, - VM_CLASSES_CHART_LOADED_CLASSES_LABEL, VM_INFO_TAB_CLASSES, + VM_CLASSES_HEADER, + + VM_CLASSES_CHART_TIME_LABEL, + VM_CLASSES_CHART_CLASSES_LABEL, + VM_CLASSES_CHART_SIZE_LABEL, + + VM_CLASSES_CHART_LOADED_CLASSES_LENGEND, + VM_CLASSES_CHART_LOADED_BYTES_LENGEND, + VM_CLASSES_CHART_UNLOADED_CLASSES_LENGEND, + VM_CLASSES_CHART_UNLOADED_BYTES_LENGEND, ; public static final String RESOURCE_BUNDLE =
--- a/vm-classstat/client-core/src/main/resources/com/redhat/thermostat/vm/classstat/client/locale/strings.properties Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-core/src/main/resources/com/redhat/thermostat/vm/classstat/client/locale/strings.properties Mon Jun 27 12:24:03 2016 -0400 @@ -1,4 +1,11 @@ -VM_LOADED_CLASSES = Loaded Classes -VM_CLASSES_CHART_REAL_TIME_LABEL = Time -VM_CLASSES_CHART_LOADED_CLASSES_LABEL = Number of loaded classes -VM_INFO_TAB_CLASSES = Classes \ No newline at end of file +VM_INFO_TAB_CLASSES = Classes +VM_CLASSES_HEADER = Classes + +VM_CLASSES_CHART_TIME_LABEL = Time +VM_CLASSES_CHART_CLASSES_LABEL = Number of classes +VM_CLASSES_CHART_SIZE_LABEL = Size (MiB) + +VM_CLASSES_CHART_LOADED_CLASSES_LENGEND = Loaded Classes +VM_CLASSES_CHART_LOADED_BYTES_LENGEND = Loaded Size +VM_CLASSES_CHART_UNLOADED_CLASSES_LENGEND = Unloaded Classes +VM_CLASSES_CHART_UNLOADED_BYTES_LENGEND = Unloaded Size
--- a/vm-classstat/client-core/src/test/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatControllerTest.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-core/src/test/java/com/redhat/thermostat/vm/classstat/client/core/internal/VmClassStatControllerTest.java Mon Jun 27 12:24:03 2016 -0400 @@ -37,8 +37,10 @@ package com.redhat.thermostat.vm.classstat.client.core.internal; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.isA; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -46,10 +48,10 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import com.redhat.thermostat.client.core.experimental.Duration; import org.junit.Test; import org.mockito.ArgumentCaptor; +import com.redhat.thermostat.client.core.experimental.Duration; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ApplicationService; @@ -67,7 +69,11 @@ @Test public void testChartUpdate() { - VmClassStat stat1 = new VmClassStat("foo-agent", "vmId", 12345, 1234); + final long SOME_TIMESTAMP = 12345; + final int SOME_VALUE = 1234; + + VmClassStat stat1 = new VmClassStat("foo-agent", "vmId", SOME_TIMESTAMP, + SOME_VALUE, SOME_VALUE, SOME_VALUE, SOME_VALUE, SOME_VALUE); List<VmClassStat> stats = new ArrayList<VmClassStat>(); stats.add(stat1); @@ -106,7 +112,7 @@ verify(timer).start(); timerActionCaptor.getValue().run(); - verify(view).addClassCount(any(List.class)); + verify(view, times(4)).addClassData(isA(String.class), isA(List.class)); l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.HIDDEN));
--- a/vm-classstat/client-swing/src/main/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanel.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-swing/src/main/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanel.java Mon Jun 27 12:24:03 2016 -0400 @@ -37,33 +37,22 @@ package com.redhat.thermostat.vm.classstat.client.swing; import java.awt.Component; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.Callable; import javax.swing.SwingUtilities; import com.redhat.thermostat.client.core.experimental.Duration; -import com.redhat.thermostat.client.swing.components.experimental.SingleValueChartPanel; -import com.redhat.thermostat.common.model.Range; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.NumberAxis; -import org.jfree.chart.axis.NumberTickUnit; -import org.jfree.chart.axis.TickUnits; -import org.jfree.data.RangeType; -import org.jfree.data.time.FixedMillisecond; -import org.jfree.data.time.RegularTimePeriod; -import org.jfree.data.time.TimeSeries; -import org.jfree.data.time.TimeSeriesCollection; - +import com.redhat.thermostat.client.swing.EdtHelper; import com.redhat.thermostat.client.swing.SwingComponent; import com.redhat.thermostat.client.swing.components.HeaderPanel; +import com.redhat.thermostat.client.swing.components.experimental.MultiChartPanel; import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ActionNotifier; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.storage.model.DiscreteTimeData; import com.redhat.thermostat.vm.classstat.client.core.VmClassStatView; @@ -73,62 +62,33 @@ private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - private static final int DEFAULT_VALUE = 10; - private static final TimeUnit DEFAULT_UNIT = TimeUnit.MINUTES; - - private Duration duration; + private final HeaderPanel visiblePanel; - private HeaderPanel visiblePanel; - - private final TimeSeriesCollection dataset = new TimeSeriesCollection(); + private final MultiChartPanel multiChartPanel; - private SingleValueChartPanel chartPanel; - - private ActionNotifier<UserAction> userActionActionNotifier = new ActionNotifier<VmClassStatView.UserAction>(this); - - private final ActionNotifier<Action> notifier = new ActionNotifier<Action>(this); + private MultiChartPanel.DataGroup GROUP_NUMBER; + private MultiChartPanel.DataGroup GROUP_SIZE; public VmClassStatPanel() { visiblePanel = new HeaderPanel(); - // any name works - dataset.addSeries(new TimeSeries("class-stat")); - duration = new Duration(DEFAULT_VALUE, DEFAULT_UNIT); - - visiblePanel.setHeader(t.localize(LocaleResources.VM_LOADED_CLASSES)); + visiblePanel.setHeader(t.localize(LocaleResources.VM_CLASSES_HEADER)); - JFreeChart chart = ChartFactory.createTimeSeriesChart( - null, - t.localize(LocaleResources.VM_CLASSES_CHART_REAL_TIME_LABEL).getContents(), - t.localize(LocaleResources.VM_CLASSES_CHART_LOADED_CLASSES_LABEL).getContents(), - dataset, - false, false, false); + String xAxisLabel = t.localize(LocaleResources.VM_CLASSES_CHART_TIME_LABEL).getContents(); + String classesAxisLabel = t.localize(LocaleResources.VM_CLASSES_CHART_CLASSES_LABEL).getContents(); + String sizeAxisLabel = t.localize(LocaleResources.VM_CLASSES_CHART_SIZE_LABEL).getContents(); + + multiChartPanel = new MultiChartPanel(); - TickUnits tickUnits = new TickUnits(); - tickUnits.add(new NumberTickUnit(1)); - tickUnits.add(new NumberTickUnit(10)); - tickUnits.add(new NumberTickUnit(100)); - tickUnits.add(new NumberTickUnit(1000)); - tickUnits.add(new NumberTickUnit(10000)); - tickUnits.add(new NumberTickUnit(100000)); - tickUnits.add(new NumberTickUnit(1000000)); + GROUP_NUMBER = multiChartPanel.createGroup(); + GROUP_SIZE = multiChartPanel.createGroup(); + + multiChartPanel.setDomainAxisLabel(xAxisLabel); - NumberAxis axis = (NumberAxis) chart.getXYPlot().getRangeAxis(); - axis.setStandardTickUnits(tickUnits); - axis.setRangeType(RangeType.POSITIVE); - axis.setAutoRangeMinimumSize(10); - - chartPanel = new SingleValueChartPanel(chart, duration); + multiChartPanel.getRangeAxis(GROUP_NUMBER).setLabel(classesAxisLabel); + multiChartPanel.getRangeAxis(GROUP_SIZE).setLabel(sizeAxisLabel); - visiblePanel.setContent(chartPanel); - - chartPanel.addPropertyChangeListener(SingleValueChartPanel.PROPERTY_VISIBLE_TIME_RANGE, new PropertyChangeListener() { - @Override - public void propertyChange(final PropertyChangeEvent evt) { - duration = (Duration) evt.getNewValue(); - userActionActionNotifier.fireAction(UserAction.USER_CHANGED_TIME_RANGE); - } - }); + visiblePanel.setContent(multiChartPanel); new ComponentVisibilityNotifier().initialize(visiblePanel, notifier); } @@ -144,42 +104,71 @@ } @Override - public void addClassCount(List<DiscreteTimeData<Long>> data) { - final List<DiscreteTimeData<Long>> copy = new ArrayList<>(data); + public void addClassChart(final Group group, final String tag, final LocalizedString name) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + multiChartPanel.addChart(getGroup(group), tag, name); + multiChartPanel.showChart(getGroup(group), tag); + } + }); + } + @Override + public void removeClassChart(final Group group, final String tag) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - TimeSeries series = dataset.getSeries(0); - for (DiscreteTimeData<Long> data: copy) { - RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis()); - if (series.getDataItem(period) == null) { - series.add(period, data.getData(), false); - } - } - series.fireSeriesChanged(); + multiChartPanel.hideChart(getGroup(group), tag); + multiChartPanel.removeChart(getGroup(group), tag); } }); + } + private MultiChartPanel.DataGroup getGroup(Group group) { + switch (group) { + case NUMBER: + return GROUP_NUMBER; + case SIZE: + return GROUP_SIZE; + default: + throw new AssertionError("Unknown data group"); + } } @Override - public void addUserActionListener(final ActionListener<UserAction> listener) { - userActionActionNotifier.addActionListener(listener); + public void addClassData(final String tag, final List<DiscreteTimeData<? extends Number>> data) { + final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + multiChartPanel.addData(tag, copy); + } + }); } @Override - public void removeUserActionListener(final ActionListener<UserAction> listener) { - userActionActionNotifier.removeActionListener(listener); + public void clearMemoryData(final String tag) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + multiChartPanel.clearData(tag); + } + }); } @Override public Duration getUserDesiredDuration() { - return duration; - } - - @Override - public void setVisibleDataRange(final int time, final TimeUnit unit) { - chartPanel.setTimeRangeToShow(time, unit); + try { + return new EdtHelper().callAndWait(new Callable<Duration>() { + @Override + public Duration call() throws Exception { + return multiChartPanel.getUserDesiredDuration(); + } + }); + } catch (InvocationTargetException | InterruptedException e) { + e.printStackTrace(); + return null; + } } @Override @@ -188,17 +177,6 @@ } @Override - public void clearClassCount() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - TimeSeries series = dataset.getSeries(0); - series.clear(); - } - }); - } - - @Override public Component getUiComponent() { return visiblePanel; }
--- a/vm-classstat/client-swing/src/test/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanelTest.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/client-swing/src/test/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanelTest.java Mon Jun 27 12:24:03 2016 -0400 @@ -36,51 +36,47 @@ package com.redhat.thermostat.vm.classstat.client.swing; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import java.util.ArrayList; +import java.util.Date; import java.util.List; - -import javax.swing.JPanel; - -import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; +import java.util.concurrent.TimeUnit; -import org.fest.swing.edt.FailOnThreadViolationRepaintManager; -import org.fest.swing.edt.GuiActionRunner; -import org.fest.swing.edt.GuiTask; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; -import com.redhat.thermostat.annotations.internal.CacioTest; +import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.storage.model.DiscreteTimeData; +import com.redhat.thermostat.vm.classstat.client.core.VmClassStatView; -@Category(CacioTest.class) -@RunWith(CacioFESTRunner.class) public class VmClassStatPanelTest { - @BeforeClass - public static void setUpOnce() { - FailOnThreadViolationRepaintManager.install(); - } - - @Test - public void testAddDataTwice() { - GuiActionRunner.execute(new GuiTask() { + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { @Override - protected void executeInEDT() throws Throwable { - VmClassStatPanel panel = new VmClassStatPanel(); - List<DiscreteTimeData<Long>> data = new ArrayList<>(); - panel.addClassCount(data); - int numComponents = ((JPanel)panel.getUiComponent()).getComponentCount(); - assertTrue(numComponents > 0); - panel.addClassCount(data); - assertEquals(numComponents, ((JPanel)panel.getUiComponent()).getComponentCount()); + public void run() { + JFrame frame = new JFrame("Test"); + + VmClassStatPanel classPanel = new VmClassStatPanel(); + + List<DiscreteTimeData<? extends Number>> data = new ArrayList<DiscreteTimeData<? extends Number>>(); + data.add(new DiscreteTimeData<>(new Date().getTime(), 10l)); + data.add(new DiscreteTimeData<>(new Date().getTime() + TimeUnit.MINUTES.toMillis(1), 1000l)); + + classPanel.addClassChart(VmClassStatView.Group.NUMBER, "classes", new LocalizedString("classes")); + classPanel.addClassData("classes", data); + + List<DiscreteTimeData<? extends Number>> data2 = new ArrayList<DiscreteTimeData<? extends Number>>(); + data2.add(new DiscreteTimeData<Number>(new Date().getTime(), 10)); + data2.add(new DiscreteTimeData<Number>(new Date().getTime() + TimeUnit.MINUTES.toMillis(1), 20)); + classPanel.addClassChart(VmClassStatView.Group.SIZE, "size", new LocalizedString("size")); + classPanel.addClassData("size", data2); + + frame.add(classPanel.getUiComponent()); + frame.pack(); + frame.setVisible(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }); } - }
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/VmClassStatDAO.java Mon Jun 27 12:24:03 2016 -0400 @@ -49,10 +49,19 @@ public interface VmClassStatDAO { static final Key<Long> loadedClassesKey = new Key<>("loadedClasses"); + static final Key<Long> loadedBytesKey = new Key<>("loadedBytes"); + static final Key<Long> unloadedClassesKey = new Key<>("unloadedClasses"); + static final Key<Long> unloadedBytesKey = new Key<>("unloadedBytes"); + static final Key<Long> classLoadTimeKey = new Key<>("classLoadTime"); static final Category<VmClassStat> vmClassStatsCategory = new Category<>( "vm-class-stats", VmClassStat.class, - Arrays.<Key<?>>asList(Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey), Arrays.<Key<?>>asList(Key.TIMESTAMP)); + Arrays.<Key<?>>asList( + Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, + loadedClassesKey, loadedBytesKey, + unloadedClassesKey, unloadedBytesKey, + classLoadTimeKey), + Arrays.<Key<?>>asList(Key.TIMESTAMP)); public List<VmClassStat> getLatestClassStats(VmRef ref, long since);
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImpl.java Mon Jun 27 12:24:03 2016 -0400 @@ -60,12 +60,20 @@ // ADD vm-class-stats SET 'agentId' = ?s , \ // 'vmId' = ?s , \ // 'timeStamp' = ?l , \ - // 'loadedClasses' = ?l + // 'loadedClasses' = ?l , \ + // 'loadedBytes' = ?l , \ + // 'unloadedClasses' = ?l , \ + // 'unloadedBytes' = ?l , \ + // 'classLoadTime' = ?l static final String DESC_ADD_VM_CLASS_STAT = "ADD " + vmClassStatsCategory.getName() + " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + "'" + Key.VM_ID.getName() + "' = ?s , " + "'" + Key.TIMESTAMP.getName() + "' = ?l , " + - "'" + loadedClassesKey.getName() + "' = ?l"; + "'" + loadedClassesKey.getName() + "' = ?l , " + + "'" + loadedBytesKey.getName() + "' = ?l , " + + "'" + unloadedClassesKey.getName() + "' = ?l , " + + "'" + unloadedBytesKey.getName() + "' = ?l , " + + "'" + classLoadTimeKey.getName() + "' = ?l"; private final Storage storage; private final VmLatestPojoListGetter<VmClassStat> latestGetter; @@ -100,6 +108,10 @@ prepared.setString(1, stat.getVmId()); prepared.setLong(2, stat.getTimeStamp()); prepared.setLong(3, stat.getLoadedClasses()); + prepared.setLong(4, stat.getLoadedBytes()); + prepared.setLong(5, stat.getUnloadedClasses()); + prepared.setLong(6, stat.getUnloadedBytes()); + prepared.setLong(7, stat.getClassLoadTime()); prepared.execute(); } catch (DescriptorParsingException e) { logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e);
--- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/model/VmClassStat.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/model/VmClassStat.java Mon Jun 27 12:24:03 2016 -0400 @@ -44,19 +44,39 @@ @Entity public class VmClassStat extends BasePojo implements TimeStampedPojo { + // See the jdk sources for more information: + // - jdk/src/share/classes/sun/tools/jstat/resources/jstat_options + // - jdk/src/share/classes/sun/tools/jstat/resources/jstat_unsupported_options + + public static final int UNKNOWN = -1; + private String vmId; private long timestamp; private long loadedClasses; + private long loadedBytes; + private long unloadedClasses; + private long unloadedBytes; + private long classLoadTime; public VmClassStat() { - this(null, null, -1, -1); + this(null, null, UNKNOWN, + UNKNOWN, UNKNOWN, + UNKNOWN, UNKNOWN, + UNKNOWN); } - public VmClassStat(String writerId, String vmId, long timestamp, long loadedClasses) { + public VmClassStat(String writerId, String vmId, long timestamp, + long loadedClasses, long loadedBytes, + long unloadedClasses, long unloadedBytes, + long classLoadTime) { super(writerId); this.vmId = vmId; this.timestamp = timestamp; this.loadedClasses = loadedClasses; + this.loadedBytes = loadedBytes; + this.unloadedClasses = unloadedClasses; + this.unloadedBytes = unloadedBytes; + this.classLoadTime = classLoadTime; } @Persist @@ -80,6 +100,7 @@ this.timestamp = timestamp; } + /** Number of classes loaded */ @Persist public long getLoadedClasses() { return loadedClasses; @@ -89,5 +110,49 @@ public void setLoadedClasses(long loadedClasses) { this.loadedClasses = loadedClasses; } + + /** Accumulated Size of classes loaded */ + @Persist + public long getLoadedBytes() { + return loadedBytes; + } + + @Persist + public void setLoadedBytes(long bytes) { + this.loadedBytes = bytes; + } + + /** Number of classes unloaded */ + @Persist + public long getUnloadedClasses() { + return unloadedClasses; + } + + @Persist + public void setUnloadedClasses(long classes) { + this.unloadedClasses = classes; + } + + /** Accumulated size of classes unloaded */ + @Persist + public long getUnloadedBytes() { + return unloadedBytes; + } + + @Persist + public void setUnloadedBytes(long bytes) { + this.unloadedBytes = bytes; + } + + /** Accumulated time for class loading. In seconds */ + @Persist + public long getClassLoadTime() { + return classLoadTime; + } + + @Persist + public void setClassLoadTime(long seconds) { + this.classLoadTime = seconds; + } + } -
--- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java Fri Jun 24 12:17:11 2016 -0400 +++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOTest.java Mon Jun 27 12:24:03 2016 -0400 @@ -67,13 +67,22 @@ private static final Long TIMESTAMP = 1234L; private static final String VM_ID = "vmId"; private static final Long LOADED_CLASSES = 12345L; + private static final Long LOADED_BYTES = 2345L; + private static final Long UNLOADED_CLASSES = 3456L; + private static final Long UNLOADED_BYTES = 4567L; + private static final Long CLASS_LOAD_TIME = 5678L; @Test public void testStatementDescriptorsAreSane() { String addVmClassStat = "ADD vm-class-stats SET 'agentId' = ?s , " + "'vmId' = ?s , " + "'timeStamp' = ?l , " + - "'loadedClasses' = ?l"; + "'loadedClasses' = ?l , " + + "'loadedBytes' = ?l , " + + "'unloadedClasses' = ?l , " + + "'unloadedBytes' = ?l , " + + "'classLoadTime' = ?l"; + assertEquals(addVmClassStat, VmClassStatDAOImpl.DESC_ADD_VM_CLASS_STAT); } @@ -85,7 +94,11 @@ assertTrue(keys.contains(new Key<Integer>("vmId"))); assertTrue(keys.contains(new Key<Long>("timeStamp"))); assertTrue(keys.contains(new Key<Long>("loadedClasses"))); - assertEquals(4, keys.size()); + assertTrue(keys.contains(new Key<Long>("loadedBytes"))); + assertTrue(keys.contains(new Key<Long>("unloadedClasses"))); + assertTrue(keys.contains(new Key<Long>("unloadedBytes"))); + assertTrue(keys.contains(new Key<Long>("classLoadTime"))); + assertEquals(8, keys.size()); } @Test @@ -134,7 +147,10 @@ } private VmClassStat getClassStat() { - return new VmClassStat("foo-agent", VM_ID, TIMESTAMP, LOADED_CLASSES); + return new VmClassStat("foo-agent", VM_ID, TIMESTAMP, + LOADED_CLASSES, LOADED_BYTES, + UNLOADED_CLASSES, UNLOADED_BYTES, + CLASS_LOAD_TIME); } @SuppressWarnings("unchecked") @@ -145,7 +161,8 @@ PreparedStatement<VmClassStat> add = mock(PreparedStatement.class); when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add); - VmClassStat stat = new VmClassStat("foo-agent", VM_ID, TIMESTAMP, LOADED_CLASSES); + VmClassStat stat = new VmClassStat("foo-agent", VM_ID, TIMESTAMP, + LOADED_CLASSES, LOADED_BYTES, UNLOADED_CLASSES, UNLOADED_BYTES, CLASS_LOAD_TIME); VmClassStatDAO dao = new VmClassStatDAOImpl(storage); dao.putVmClassStat(stat); @@ -160,6 +177,10 @@ verify(add).setString(1, stat.getVmId()); verify(add).setLong(2, stat.getTimeStamp()); verify(add).setLong(3, stat.getLoadedClasses()); + verify(add).setLong(4, stat.getLoadedBytes()); + verify(add).setLong(5, stat.getUnloadedClasses()); + verify(add).setLong(6, stat.getUnloadedBytes()); + verify(add).setLong(7, stat.getClassLoadTime()); verify(add).execute(); verifyNoMoreInteractions(add); }