# HG changeset patch # User James Aziz # Date 1467301014 14400 # Node ID 8a65bb11a6f975cf347c31b84246286d5dc32285 # Parent c5a118f7a7e29ebe08631333265b246f5efce763 Add profiler treemap PR3070 Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-June/020062.html Original-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-December/017148.html diff -r c5a118f7a7e2 -r 8a65bb11a6f9 client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapComponent.java --- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapComponent.java Thu Jun 30 11:35:49 2016 -0400 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapComponent.java Thu Jun 30 11:36:54 2016 -0400 @@ -76,8 +76,6 @@ import javax.swing.border.LineBorder; import com.redhat.thermostat.client.swing.ThermostatSwingCursors; -import com.redhat.thermostat.common.Size; -import com.redhat.thermostat.common.Size.Unit; /** * This class allows to represent a hierarchical data structure as a TreeMap. @@ -145,7 +143,7 @@ /** * Variable in which store last resize event call time. */ - private static long lastCall = 0; + private long lastCall = 0; /** * Wait time in millisec to resize the TreeMap. @@ -162,7 +160,7 @@ * This object stores the last clicked rectangle in the TreeMap, in order to * repaint it when another rectangle will be selected. */ - private static Comp lastClicked; + private Comp lastClicked; /** * List of objects observing this. @@ -591,7 +589,7 @@ /** * Switch the component's border style to the one given in input. * - * @param borderStyle the border style to use + * @param newBorderStyle the border style to use */ public void setBorderStyle(int newBorderStyle) { Border border; diff -r c5a118f7a7e2 -r 8a65bb11a6f9 client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapComponentTest.java --- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapComponentTest.java Thu Jun 30 11:35:49 2016 -0400 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapComponentTest.java Thu Jun 30 11:36:54 2016 -0400 @@ -36,18 +36,14 @@ package com.redhat.thermostat.client.swing.components.experimental; -import org.jfree.chart.renderer.category.GradientBarPainter; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.KeyStroke; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; import java.awt.BorderLayout; import java.awt.Font; import java.awt.event.ActionEvent; @@ -58,13 +54,18 @@ import java.util.List; import java.util.Random; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; public class TreeMapComponentTest { @@ -521,6 +522,10 @@ modelA.addChild(new TreeMapNode("AA", 2.0)); modelA.addChild(new TreeMapNode("AB", 3.0)); + final TreeMapNode modelC = new TreeMapNode("C", 1.0); + modelC.addChild(new TreeMapNode("CA", 2.0)); + modelC.addChild(new TreeMapNode("CB", 3.0)); + final TreeMapNode modelB = new TreeMapNode("B", 5.0); final Random generator = new Random(); for (int i = 0; i < 100; i++) { @@ -535,19 +540,29 @@ // FIXME this hack should not be needed UIManager.put("thermostat-default-font", Font.decode(Font.MONOSPACED)); - final TreeMapComponent treeMap = new TreeMapComponent(); - treeMap.setToolTipRenderer(new WeightRenderer()); - treeMap.setModel(modelA); + JPanel container = new JPanel(new BorderLayout()); + final JTabbedPane tabbedPane = new JTabbedPane(); - JPanel container = new JPanel(new BorderLayout()); + final TreeMapComponent treeMapA = new TreeMapComponent(); + treeMapA.setToolTipRenderer(new WeightRenderer()); + treeMapA.setModel(modelA); + + final TreeMapComponent treeMapC = new TreeMapComponent(); + treeMapC.setToolTipRenderer(new WeightRenderer()); + treeMapC.setModel(modelC); JPanel buttonPanel = new JPanel(); JButton changeModelButton = new JButton("Change model"); changeModelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - TreeMapNode newModel = treeMap.getTreeMapRoot() == modelA ? modelB : modelA; - treeMap.setModel(newModel); + if (tabbedPane.getSelectedIndex() == 0) { + TreeMapNode newModel = treeMapA.getTreeMapRoot() == modelA ? modelB : modelA; + treeMapA.setModel(newModel); + } else { + TreeMapNode newModel = treeMapC.getTreeMapRoot() == modelC ? modelB : modelC; + treeMapC.setModel(newModel); + } } }); buttonPanel.add(changeModelButton); @@ -556,10 +571,15 @@ addChildToRootButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - TreeMapNode currentModel = treeMap.getTreeMapRoot(); - currentModel.addChild(new TreeMapNode("new", 5.0)); - - treeMap.setModel(currentModel); + if (tabbedPane.getSelectedIndex() == 0) { + TreeMapNode currentModel = treeMapA.getTreeMapRoot(); + currentModel.addChild(new TreeMapNode("new", 5.0)); + treeMapA.setModel(currentModel); + } else { + TreeMapNode currentModel = treeMapC.getTreeMapRoot(); + currentModel.addChild(new TreeMapNode("new", 5.0)); + treeMapC.setModel(currentModel); + } } }); buttonPanel.add(addChildToRootButton); @@ -568,21 +588,34 @@ addRandomNodeButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - TreeMapNode currentModel = treeMap.getTreeMapRoot(); - List allNodes = new ArrayList<>(); - findAllNodes(allNodes, currentModel); - TreeMapNode parent = allNodes.get(generator.nextInt(allNodes.size())); - double weight = Math.pow(10, generator.nextInt(4)); - parent.addChild(new TreeMapNode("rand", weight)); + if (tabbedPane.getSelectedIndex() == 0) { + TreeMapNode currentModel = treeMapA.getTreeMapRoot(); + List allNodes = new ArrayList<>(); + findAllNodes(allNodes, currentModel); + TreeMapNode parent = allNodes.get(generator.nextInt(allNodes.size())); + double weight = Math.pow(10, generator.nextInt(4)); + parent.addChild(new TreeMapNode("rand", weight)); - treeMap.setModel(currentModel); + treeMapA.setModel(currentModel); + } else { + TreeMapNode currentModel = treeMapC.getTreeMapRoot(); + List allNodes = new ArrayList<>(); + findAllNodes(allNodes, currentModel); + TreeMapNode parent = allNodes.get(generator.nextInt(allNodes.size())); + double weight = Math.pow(10, generator.nextInt(4)); + parent.addChild(new TreeMapNode("rand", weight)); + + treeMapC.setModel(currentModel); + } } }); buttonPanel.add(addRandomNodeButton); container.add(buttonPanel, BorderLayout.PAGE_START); - container.add(treeMap, BorderLayout.CENTER); + tabbedPane.addTab("TMA", treeMapA); + tabbedPane.addTab("TMC", treeMapC); + container.add(tabbedPane, BorderLayout.CENTER); mainWindow.add(container, BorderLayout.CENTER); mainWindow.setSize(500, 200); diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/Activator.java --- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/Activator.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/Activator.java Thu Jun 30 11:36:54 2016 -0400 @@ -61,6 +61,9 @@ @Override public void start(final BundleContext context) throws Exception { + VmProfileTreeMapViewProvider vmProfileTreeMapViewProvider = new SwingVmProfileTreeMapViewProvider(); + context.registerService(VmProfileTreeMapViewProvider.class.getName(), + vmProfileTreeMapViewProvider, null); Class[] deps = new Class[] { ApplicationService.class, @@ -69,6 +72,7 @@ VmInfoDAO.class, ProfileDAO.class, RequestQueue.class, + VmProfileTreeMapViewProvider.class, }; tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() { @@ -80,8 +84,11 @@ VmInfoDAO vmInfoDao = (VmInfoDAO) services.get(VmInfoDAO.class.getName()); ProfileDAO profileDao = (ProfileDAO) services.get(ProfileDAO.class.getName()); RequestQueue queue = (RequestQueue) services.get(RequestQueue.class.getName()); + VmProfileTreeMapViewProvider treeMapViewProvider = (VmProfileTreeMapViewProvider) services + .get(VmProfileTreeMapViewProvider.class.getName()); - InformationService profileService = new VmProfileService(service, notifier, agentInfoDao, vmInfoDao, profileDao, queue); + InformationService profileService = new VmProfileService(service, notifier, + agentInfoDao, vmInfoDao, profileDao, queue, treeMapViewProvider); Hashtable properties = new Hashtable<>(); properties.put(Constants.GENERIC_SERVICE_CLASSNAME, VmRef.class.getName()); diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResources.java --- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResources.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResources.java Thu Jun 30 11:36:54 2016 -0400 @@ -54,6 +54,8 @@ STOPPING_PROFILING, PROFILER_LIST_ITEM, + PROFILER_RESULTS_TABLE, + PROFILER_RESULTS_TREEMAP, PROFILER_RESULTS_METHOD, PROFILER_RESULTS_PERCENTAGE_TIME, PROFILER_RESULTS_TIME, diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ProfilingResultNodeDataExtractor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ProfilingResultNodeDataExtractor.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +import java.util.Collection; +import java.util.regex.Pattern; + +import com.redhat.thermostat.client.swing.components.experimental.NodeDataExtractor; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; + +public class ProfilingResultNodeDataExtractor implements NodeDataExtractor { + + static final String DELIMITER = "."; + + @Override + public String[] getNodes(MethodInfo methodInfo) { + return methodInfo.decl.getName().split(Pattern.quote(DELIMITER)); + } + + @Override + public double getWeight(MethodInfo methodInfo) { + return methodInfo.totalTimeInMillis; + } + + @Override + public Collection getAsCollection(ProfilingResult result) { + return result.getMethodInfo(); + } +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileTreeMapView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileTreeMapView.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,91 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +import java.awt.BorderLayout; +import java.awt.Component; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.experimental.TreeMap; +import com.redhat.thermostat.client.swing.components.experimental.TreeMapComponent; +import com.redhat.thermostat.client.swing.components.experimental.TreeMapNode; +import com.redhat.thermostat.client.swing.components.experimental.TreeMapToolbar; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; + +public class SwingVmProfileTreeMapView extends VmProfileTreeMapView implements SwingComponent { + private TreeMapComponent treeMapComp; + private final JPanel panel; + + public SwingVmProfileTreeMapView() { + panel = new JPanel(); + treeMapComp = new TreeMapComponent(); + treeMapComp.setToolTipRenderer(new TimeToolTipRenderer()); + panel.setLayout(new BorderLayout()); + } + + @Override + public void display(final ProfilingResult result) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TreeMap treeMap = + new TreeMap<>(result, new ProfilingResultNodeDataExtractor()); + treeMapComp.setModel(treeMap.getRoot()); + panel.removeAll(); + panel.add(treeMapComp, BorderLayout.CENTER); + panel.add(new TreeMapToolbar(treeMapComp), BorderLayout.NORTH); + panel.revalidate(); + panel.repaint(); + } + }); + } + + @Override + public Component getUiComponent() { + return panel; + } + + public static class TimeToolTipRenderer implements TreeMapComponent.ToolTipRenderer { + @Override + public String render(TreeMapNode node) { + return node.getLabel() + " - " + (long) node.getRealWeight() + "ms"; + } + } +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileTreeMapViewProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileTreeMapViewProvider.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +public class SwingVmProfileTreeMapViewProvider implements VmProfileTreeMapViewProvider { + + @Override + public VmProfileTreeMapView createView() { + return new SwingVmProfileTreeMapView(); + } +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileView.java --- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileView.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileView.java Thu Jun 30 11:36:54 2016 -0400 @@ -59,6 +59,7 @@ import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JToggleButton; import javax.swing.ListSelectionModel; @@ -84,8 +85,9 @@ import com.redhat.thermostat.client.ui.Palette; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.utils.MethodDescriptorConverter.MethodDeclaration; import com.redhat.thermostat.common.utils.StringUtils; -import com.redhat.thermostat.common.utils.MethodDescriptorConverter.MethodDeclaration; +import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; @@ -106,6 +108,7 @@ private final CopyOnWriteArrayList> listeners = new CopyOnWriteArrayList<>(); private HeaderPanel mainContainer; + private JTabbedPane tabPane; private ActionToggleButton toggleButton; @@ -136,6 +139,7 @@ public SwingVmProfileView() { listModel = new DefaultListModel<>(); + tabPane = new JTabbedPane(); toggleButton = new ActionToggleButton(START_ICON, STOP_ICON, translator.localize(LocaleResources.START_PROFILING)); toggleButton.toggleText(false); @@ -259,8 +263,10 @@ } }; - JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - profileListPane, profileTable.wrap()); + tabPane.addTab(translator.localize(LocaleResources.PROFILER_RESULTS_TABLE).getContents(), + profileTable.wrap()); + + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, profileListPane, tabPane); splitPane.setDividerLocation(SPLIT_PANE_RATIO); splitPane.setResizeWeight(0.5); @@ -416,6 +422,16 @@ } @Override + public void addTabToTabbedPane(final LocalizedString title, final Component component) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + tabPane.addTab(title.getContents(), component); + } + }); + } + + @Override public Component getUiComponent() { return mainContainer; } diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileController.java --- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileController.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileController.java Thu Jun 30 11:36:54 2016 -0400 @@ -44,6 +44,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; import com.redhat.thermostat.client.command.RequestQueue; @@ -53,6 +54,7 @@ import com.redhat.thermostat.client.core.views.BasicView; import com.redhat.thermostat.client.core.views.BasicView.Action; import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.client.swing.SwingComponent; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ApplicationService; @@ -97,6 +99,7 @@ private final VmRef vm; private VmProfileView view; + private VmProfileTreeMapView treeMapView; private Timer updater; @@ -111,15 +114,15 @@ public VmProfileController(ApplicationService service, ProgressNotifier notifier, AgentInfoDAO agentInfoDao, VmInfoDAO vmInfoDao, ProfileDAO dao, - RequestQueue queue, - VmRef vm) { - this(service, notifier, agentInfoDao, vmInfoDao, dao, queue, new SystemClock(), new SwingVmProfileView(), vm); + RequestQueue queue, VmProfileTreeMapViewProvider treeMapViewProvider, VmRef vm) { + this(service, notifier, agentInfoDao, vmInfoDao, dao, queue, new SystemClock(), + new SwingVmProfileView(), vm, treeMapViewProvider); } VmProfileController(final ApplicationService service, ProgressNotifier notifier, AgentInfoDAO agentInfoDao, VmInfoDAO vmInfoDao, ProfileDAO dao, - RequestQueue queue, Clock clock, - final VmProfileView view, VmRef vm) { + RequestQueue queue, Clock clock, final VmProfileView view, VmRef vm, + VmProfileTreeMapViewProvider treeMapViewProvider) { this.service = service; this.notifier = notifier; this.agentInfoDao = agentInfoDao; @@ -134,6 +137,10 @@ service.getApplicationCache().addAttribute(STATE_MAP_KEY, STATE_BUNDLE_MAP); } + this.treeMapView = Objects.requireNonNull(treeMapViewProvider.createView()); + view.addTabToTabbedPane(translator.localize(LocaleResources.PROFILER_RESULTS_TREEMAP), + ((SwingComponent) this.treeMapView).getUiComponent()); + // TODO dispose the timer when done updater = service.getTimerFactory().createTimer(); updater.setSchedulingType(SchedulingType.FIXED_DELAY); @@ -340,7 +347,9 @@ String profileId = selectedProfile.name; InputStream in = profileDao.loadProfileDataById(vm, profileId); ProfilingResult result = new ProfilingResultParser().parse(in); + view.setProfilingDetailData(result); + treeMapView.display(result); } @Override diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileService.java --- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileService.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileService.java Thu Jun 30 11:36:54 2016 -0400 @@ -56,16 +56,18 @@ private VmInfoDAO vmInfoDao; private ProfileDAO dao; private RequestQueue queue; + private VmProfileTreeMapViewProvider treeMapViewProvider; public VmProfileService(ApplicationService service, ProgressNotifier notifier, AgentInfoDAO agentInfoDao, VmInfoDAO vmInfoDao, ProfileDAO dao, - RequestQueue queue) { + RequestQueue queue, VmProfileTreeMapViewProvider treeMapViewProvider) { this.service = service; this.notifier = notifier; this.agentInfoDao = agentInfoDao; this.vmInfoDao = vmInfoDao; this.dao = dao; this.queue = queue; + this.treeMapViewProvider = treeMapViewProvider; } @Override @@ -81,7 +83,8 @@ @Override public InformationServiceController getInformationServiceController(VmRef ref) { - return new VmProfileController(service, notifier, agentInfoDao, vmInfoDao, dao, queue, ref); + return new VmProfileController(service, notifier, agentInfoDao, vmInfoDao, dao, queue, + treeMapViewProvider, ref); } } diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileTreeMapView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileTreeMapView.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; + +public abstract class VmProfileTreeMapView extends BasicView implements UIComponent{ + + public abstract void display(ProfilingResult result); +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileTreeMapViewProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileTreeMapViewProvider.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +import com.redhat.thermostat.client.core.views.ViewProvider; + +public interface VmProfileTreeMapViewProvider extends ViewProvider { + + @Override + public VmProfileTreeMapView createView(); +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileView.java --- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileView.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileView.java Thu Jun 30 11:36:54 2016 -0400 @@ -36,13 +36,15 @@ package com.redhat.thermostat.vm.profiler.client.swing.internal; +import java.awt.Component; import java.util.List; import java.util.Objects; +import com.redhat.thermostat.client.core.ToggleActionState; import com.redhat.thermostat.client.core.views.BasicView; import com.redhat.thermostat.client.core.views.UIComponent; -import com.redhat.thermostat.client.core.ToggleActionState; import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.shared.locale.LocalizedString; import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; public abstract class VmProfileView extends BasicView implements UIComponent { @@ -135,4 +137,6 @@ public abstract void setProfilingDetailData(ProfilingResult results); + public abstract void addTabToTabbedPane(final LocalizedString title, final Component component); + } diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/main/resources/com/redhat/thermostat/vm/profiler/client/swing/internal/strings.properties --- a/vm-profiler/client-swing/src/main/resources/com/redhat/thermostat/vm/profiler/client/swing/internal/strings.properties Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/main/resources/com/redhat/thermostat/vm/profiler/client/swing/internal/strings.properties Thu Jun 30 11:36:54 2016 -0400 @@ -14,6 +14,8 @@ STOPPING_PROFILING = Stopping profiling\u2026 PROFILER_LIST_ITEM = Session @ {1} ({0}) +PROFILER_RESULTS_TABLE = Table +PROFILER_RESULTS_TREEMAP = TreeMap PROFILER_RESULTS_METHOD = Method PROFILER_RESULTS_PERCENTAGE_TIME = Percentage PROFILER_RESULTS_TIME = Total Time ({0}) diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ActivatorTest.java --- a/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ActivatorTest.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ActivatorTest.java Thu Jun 30 11:36:54 2016 -0400 @@ -68,8 +68,8 @@ VmInfoDAO vmInfoDao = mock(VmInfoDAO.class); bundleContext.registerService(VmInfoDAO.class, vmInfoDao, null); - ProfileDAO profielDao = mock(ProfileDAO.class); - bundleContext.registerService(ProfileDAO.class, profielDao, null); + ProfileDAO profileDao = mock(ProfileDAO.class); + bundleContext.registerService(ProfileDAO.class, profileDao, null); RequestQueue requestQueue = mock(RequestQueue.class); bundleContext.registerService(RequestQueue.class, requestQueue, null); @@ -79,6 +79,7 @@ activator.start(bundleContext); assertTrue(bundleContext.isServiceRegistered(InformationService.class.getName(), VmProfileService.class)); + assertTrue(bundleContext.isServiceRegistered(VmProfileTreeMapViewProvider.class.getName(), SwingVmProfileTreeMapViewProvider.class)); activator.stop(bundleContext); } diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ProfilingResultNodeDataExtractorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ProfilingResultNodeDataExtractorTest.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.utils.MethodDescriptorConverter.MethodDeclaration; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; + +public class ProfilingResultNodeDataExtractorTest { + + private static final String[] NODES = {"foo", "bar", "jar"}; + private static final long TOTAL_TIME = 1024; + private static final int SOME_INT = 50; + private static final double DELTA = 0.01; + + private ProfilingResultNodeDataExtractor extractor; + private MethodInfo methodInfo; + private ProfilingResult result; + + @Before + public void setUp() { + extractor = new ProfilingResultNodeDataExtractor(); + + String methodName = NODES[0] + extractor.DELIMITER + NODES[1] + extractor.DELIMITER + NODES[2]; + MethodDeclaration decl = new MethodDeclaration(methodName, Arrays.asList("int"), "int"); + methodInfo = new MethodInfo(decl, TOTAL_TIME, SOME_INT); + + List methodInfos = new ArrayList<>(); + methodInfos.add(methodInfo); + methodInfos.add(new MethodInfo(new MethodDeclaration("car", Arrays.asList("char"), "char"), + SOME_INT, SOME_INT)); + result = new ProfilingResult(methodInfos); + } + + @Test + public void testGetNodes() { + String[] result = extractor.getNodes(methodInfo); + assertTrue(Arrays.equals(NODES, result)); + } + + @Test + public void testGetWeight() { + double weight = extractor.getWeight(methodInfo); + assertEquals(TOTAL_TIME, weight, DELTA); + } + + @Test + public void testGetAsCollection() { + Collection collection = extractor.getAsCollection(result); + assertEquals(2, collection.size()); + assertTrue(collection.contains(methodInfo)); + } +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/TimeToolTipRendererTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/TimeToolTipRendererTest.java Thu Jun 30 11:36:54 2016 -0400 @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2016 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 + * . + * + * 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.vm.profiler.client.swing.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.client.swing.components.experimental.TreeMap; +import com.redhat.thermostat.client.swing.components.experimental.TreeMapNode; +import com.redhat.thermostat.vm.profiler.client.swing.internal.SwingVmProfileTreeMapView.TimeToolTipRenderer; + +public class TimeToolTipRendererTest { + + private static final String ROOT_LABEL = "root"; + private static final String CHILD_LABEL = "child"; + private static final double ROOT_WEIGHT = 1024.0; + private static final double CHILD_WEIGHT = 3.14; + + private TimeToolTipRenderer renderer; + private TreeMapNode root; + + @Before + public void setUp() { + root = new TreeMapNode(ROOT_LABEL, ROOT_WEIGHT); + root.addChild(new TreeMapNode(CHILD_LABEL, CHILD_WEIGHT)); + renderer = new TimeToolTipRenderer(); + } + + @Test + public void testTimeToolTipRenderer() { + String result = renderer.render(root); + assertEquals("root - 1024ms", result); + + TreeMapNode child = TreeMap.searchNode(root, CHILD_LABEL); + assertNotNull(child); + result = renderer.render(child); + assertEquals("child - 3ms", result); + } +} diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileControllerTest.java --- a/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileControllerTest.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileControllerTest.java Thu Jun 30 11:36:54 2016 -0400 @@ -36,6 +36,8 @@ package com.redhat.thermostat.vm.profiler.client.swing.internal; +import junit.framework.Assert; + import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; @@ -52,6 +54,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.awt.Component; import java.io.ByteArrayInputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; @@ -62,8 +65,6 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import com.redhat.thermostat.common.ApplicationCache; -import org.hamcrest.core.IsNull; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -71,8 +72,10 @@ import com.redhat.thermostat.client.command.RequestQueue; import com.redhat.thermostat.client.core.progress.ProgressNotifier; import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.client.swing.SwingComponent; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ApplicationCache; import com.redhat.thermostat.common.ApplicationService; import com.redhat.thermostat.common.Clock; import com.redhat.thermostat.common.Timer; @@ -117,6 +120,7 @@ private Clock clock; private VmProfileView view; private VmRef vm; + private VmProfileTreeMapViewProvider treeMapViewProvider; private VmProfileController controller; private HostRef agent; @@ -155,12 +159,35 @@ when(vm.getHostRef()).thenReturn(agent); when(vm.getVmId()).thenReturn(VM_ID); + treeMapViewProvider = mock(VmProfileTreeMapViewProvider.class); + VmProfileTreeMapView vmProfileTreeMapView = mock(SwingVmProfileTreeMapView.class); + when(treeMapViewProvider.createView()).thenReturn(vmProfileTreeMapView); + when(((SwingComponent) vmProfileTreeMapView).getUiComponent()).thenReturn(mock(Component.class)); + AgentInformation agentInfo = new AgentInformation(); agentInfo.setAlive(true); agentInfo.setConfigListenAddress(AGENT_HOST + ":" + AGENT_PORT); when(agentInfoDao.getAgentInformation(agent)).thenReturn(agentInfo); } + @Test (expected = NullPointerException.class) + public void testMainConstructorFailsWithInvalidViewProvider() { + VmProfileTreeMapViewProvider viewProvider = mock(VmProfileTreeMapViewProvider.class); + when(viewProvider.createView()).thenReturn(null); + new VmProfileController(appService, notifier, agentInfoDao, vmInfoDao, profileDao, queue, + clock, view, vm, viewProvider); + } + + @Test + public void testMainConstructorAcceptsValidParameters() { + try { + new VmProfileController(appService, notifier, agentInfoDao, vmInfoDao, profileDao, + queue, clock, view, vm, treeMapViewProvider); + } catch (NullPointerException e) { + Assert.fail("No exception expected"); + } + } + @Test public void timerRunsWhenVisible() throws Exception { when(appCache.getAttribute(any(String.class))).thenReturn(new HashMap<>()); @@ -482,7 +509,8 @@ } private VmProfileController createController() { - return new VmProfileController(appService, notifier, agentInfoDao, vmInfoDao, profileDao, queue, clock, view, vm); + return new VmProfileController(appService, notifier, agentInfoDao, vmInfoDao, profileDao, + queue, clock, view, vm, treeMapViewProvider); } private void assertRequestEquals(Request actual, Request expected) { diff -r c5a118f7a7e2 -r 8a65bb11a6f9 vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileServiceTest.java --- a/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileServiceTest.java Thu Jun 30 11:35:49 2016 -0400 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileServiceTest.java Thu Jun 30 11:36:54 2016 -0400 @@ -50,7 +50,7 @@ public void worksWithDeadAndAliveVms() throws Exception { VmRef vm = mock(VmRef.class); - VmProfileService service = new VmProfileService(null, null, null, null, null, null); + VmProfileService service = new VmProfileService(null, null, null, null, null, null, null); Filter filter = service.getFilter(); assertTrue(filter.matches(vm));