Mercurial > hg > release > thermostat-1.6
changeset 1989:10e0b0fe84ef
Improve treemap building code
PR3059
Reviewed-by: jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-June/019844.html
Original-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-November/016974.html
author | James Aziz <jaziz@redhat.com> |
---|---|
date | Wed, 29 Jun 2016 12:23:11 -0400 |
parents | 44ded819f2bf |
children | 1ee23f6c4b50 |
files | client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/AbstractTreeAssembler.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/NodeDataExtractor.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeAssembler.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeConverter.java client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeMap.java client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/AbstractTreeAssemblerTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeConverterTest.java client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapTest.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectHistogramNodeDataExtractor.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectHistogramTreeAssembler.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapTreeMapView.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectHistogramTreeAssemblerTest.java |
diffstat | 12 files changed, 492 insertions(+), 760 deletions(-) [+] |
line wrap: on
line diff
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/AbstractTreeAssembler.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright 2012-2015 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.swing.components.experimental; - -import java.util.List; -import java.util.regex.Pattern; - -public abstract class AbstractTreeAssembler<T> implements TreeAssembler<T> { - - @Override - public abstract void buildTree(T data, TreeMapNode root); - - public static TreeMapNode processRecord(String name, String token, TreeMapNode lastProcessed) { - while (!name.equals("")) { - - String nodeId = name.split(Pattern.quote(token))[0]; - - TreeMapNode child = searchNode(lastProcessed.getChildren(), nodeId); - if (child == null) { - child = new TreeMapNode(nodeId, 0); - lastProcessed.addChild(child); - } - - lastProcessed = child; - - name = name.substring(nodeId.length()); - if (name.startsWith(".")) { - name = name.substring(1); - } - } - return lastProcessed; - } - - public static TreeMapNode searchNode(List<TreeMapNode> nodes, String nodeId) { - for (TreeMapNode node : nodes) { - if (node.getLabel().equals(nodeId)) { - return node; - } - } - return null; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/NodeDataExtractor.java Wed Jun 29 12:23:11 2016 -0400 @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2015 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.swing.components.experimental; + +import java.util.Collection; + +/** + * This interface facilitates the extraction of a collection of elements from a dataset and + * provides methods for reading information from these elements. + * + * @param <S> a dataset that aggregates elements of type {@link T} + * @param <T> an element, holding some weight and labelled by some key (e.g. a pathname) that + * expresses a delimited set of (hierarchical) nodes + */ +public interface NodeDataExtractor<S, T> { + + String getNodeSeparator(); + + String getKey(T element); + double getWeight(T element); + + Collection<T> getAsCollection(S data); +}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeAssembler.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2015 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.swing.components.experimental; - -public interface TreeAssembler<T> { - - void buildTree(T data, TreeMapNode root); -}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeConverter.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright 2012-2015 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.swing.components.experimental; - -import java.util.List; - -public class TreeConverter { - - /** - * This method builds a tree map model of the {@link T} data provided, using the - * specified {@link TreeAssembler} assembler. - * - * @return the root of the resulting tree - */ - public static <T> TreeMapNode convertToTreeMap(T data, TreeAssembler<T> assembler) { - TreeMapNode root = new TreeMapNode("", 0); - - assembler.buildTree(data, root); - // calculates weights for inner nodes - fillWeights(root); - // collapse nodes with only one child - packTree(root); - return root; - } - - /** - * This method calculates the real weights using a bottom-up traversal. The weight of a - * parent node is the sum of its children's weights. - * - * Package-private for testing purposes. - * - * @param node the root of the subtree - * @return the real weight of the root - */ - static double fillWeights(TreeMapNode node) { - if (node.getChildren().size() == 0) { - return node.getRealWeight(); - } - - double sum = 0; - for (TreeMapNode child : node.getChildren()) { - sum += fillWeights(child); - } - node.setRealWeight(sum); - return node.getRealWeight(); - } - - /** - * This method allows the collapse of a series of nodes, each with at most one child, into a - * single node placed at the root of the series. - * - * Package-private for testing purposes. - * - * @param node the root of the subtree - */ - static void packTree(TreeMapNode node) { - List<TreeMapNode> children = node.getChildren(); - if (children.size() == 1) { - TreeMapNode child = children.get(0); - node.setLabel(node.getLabel() + "." + child.getLabel()); - node.setChildren(child.getChildren()); - packTree(node); - } else { - for (TreeMapNode child : children) { - packTree(child); - } - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/experimental/TreeMap.java Wed Jun 29 12:23:11 2016 -0400 @@ -0,0 +1,149 @@ +/* + * Copyright 2012-2015 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.swing.components.experimental; + +import java.util.List; +import java.util.regex.Pattern; + +/** + * This class represents a treemap and facilitates its construction from information available in + * the {@link S} dataset. + * + * @param <S> a dataset that aggregates elements of type {@link T} + * @param <T> an element, holding some weight and labelled by some key (e.g. a pathname) that + * expresses a delimited set of (hierarchical) nodes + */ +public class TreeMap<S, T> { + + private final TreeMapNode root; + + public TreeMap(S data, NodeDataExtractor<S, T> extractor) { + root = new TreeMapNode("", 0); + buildTree(data, root, extractor); + // calculates weights for inner nodes + fillWeights(root); + // collapse nodes with only one child + packTree(root); + } + + public TreeMapNode getRoot() { + return root; + } + + private static <S, T> void buildTree(S data, TreeMapNode root, NodeDataExtractor<S, T> extractor) { + + for(T element: extractor.getAsCollection(data)) { + String key = extractor.getKey(element); + String splitToken = extractor.getNodeSeparator(); + double weight = extractor.getWeight(element); + + TreeMapNode lastProcessed = root; + while (!key.equals("")) { + + String nodeId = key.split(Pattern.quote(splitToken))[0]; + + TreeMapNode child = searchNode(lastProcessed, nodeId); + if (child == null) { + child = new TreeMapNode(nodeId, 0); + lastProcessed.addChild(child); + } + + lastProcessed = child; + + key = key.substring(nodeId.length()); + if (key.startsWith(splitToken)) { + key = key.substring(1); + } + } + lastProcessed.setRealWeight(weight); + } + } + + /** + * This method calculates the real weights using a bottom-up traversal. The weight of a + * parent node is the sum of its children's weights. + * + * Package-private for testing purposes. + * + * @param node the root of the subtree + * @return the real weight of the root + */ + static double fillWeights(TreeMapNode node) { + if (node.getChildren().size() == 0) { + return node.getRealWeight(); + } + + double sum = 0; + for (TreeMapNode child : node.getChildren()) { + sum += fillWeights(child); + } + node.setRealWeight(sum); + return node.getRealWeight(); + } + + /** + * This method allows the collapse of a series of nodes, each with at most one child, into a + * single node placed at the root of the series. + * + * Package-private for testing purposes. + * + * @param node the root of the subtree + */ + static void packTree(TreeMapNode node) { + List<TreeMapNode> children = node.getChildren(); + if (children.size() == 1) { + TreeMapNode child = children.get(0); + node.setLabel(node.getLabel() + "." + child.getLabel()); + node.setChildren(child.getChildren()); + packTree(node); + } else { + for (TreeMapNode child : children) { + packTree(child); + } + } + } + + public static TreeMapNode searchNode(TreeMapNode startingPoint, String nodeId) { + List<TreeMapNode> children = startingPoint.getChildren(); + for (TreeMapNode node : children) { + if (node.getLabel().equals(nodeId)) { + return node; + } + } + return null; + } +}
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/AbstractTreeAssemblerTest.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright 2012-2015 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.swing.components.experimental; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -public class AbstractTreeAssemblerTest { - - final private String SOME_ROOT_LABEL = "root"; - final private double SOME_ROOT_WEIGHT = 25.0; - final private String SPLIT_TOKEN = "."; - - private TreeMapNode root; - - @Before - public void setup() { - root = new TreeMapNode(SOME_ROOT_LABEL, SOME_ROOT_WEIGHT); - } - - @Test - public void testProcessRecord() { - String class1 = "com.Class1"; - AbstractTreeAssembler.processRecord(class1, SPLIT_TOKEN, root); - - List<TreeMapNode> children = root.getChildren(); - assertEquals(1, children.size()); - assertEquals("com", children.get(0).getLabel()); - - children = children.get(0).getChildren(); - assertEquals(1, children.size()); - assertEquals("Class1", children.get(0).getLabel()); - assertEquals(0, children.get(0).getChildren().size()); - - String class2 = "com.Class2"; - AbstractTreeAssembler.processRecord(class2, SPLIT_TOKEN, root); - - children = root.getChildren(); - assertEquals(1, children.size()); - assertEquals("com", children.get(0).getLabel()); - - children = children.get(0).getChildren(); - assertEquals(2, children.size()); - assertNotNull(AbstractTreeAssembler.searchNode(children, "Class1")); - assertNotNull(AbstractTreeAssembler.searchNode(children, "Class2")); - assertEquals(0, children.get(0).getChildren().size()); - assertEquals(0, children.get(1).getChildren().size()); - } -}
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeConverterTest.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -/* - * Copyright 2012-2015 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.swing.components.experimental; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.common.Pair; - -public class TreeConverterTest { - - final private String SPLIT_TOKEN = "."; - final private String SOME_ROOT_LABEL = "root"; - final private double SOME_ROOT_WEIGHT = 25.0; - final private double DELTA = 0.01; - final private double SOME_WEIGHT = 3.14; - - private ArrayList<Pair<String, Double>> data; - private TreeMapNode root; - - @Before - public void setUp() { - /* - * This is the classes structure used for the test and built using - * the data. Nodes are compacted at the point of branching - * so for example the node relative to "example2.package1.Class1" is - * still just one node "example2.package1.Class1" but the node relative - * to "com.example1.package1.Class1" branches at "com" so becomes the - * common parent node "com" with children "example1" and "example2", - * and so forth: - * - * ________com_______ java - * / \ | - * __example1__ example2 lang - * / \ | | - * package1 package2 package1 Object - * / \ | | - * Class1 Class2 Class3 Class4 - * - * - * - * - * Expected tree after conversion: - * - * ________________________root_______________ - * / \ - * ________com_______ java.lang.Object - * / \ - * __example1__ example2.package1.Class4 - * / \ - * package1 package2.Class3 - * / \ - * Class1 Class2 - * - */ - final String[] classes = { - "com.example1.package1.Class1", - "com.example1.package1.Class2", - "com.example1.package2.Class3", - "com.example2.package1.Class4", - "example2.package1.Class1", - "java.lang.Object", - "repeat1.repeat1.RepeatClass", - "repeat2.repeat2A.RepeatClass", - "repeat2.repeat2B.RepeatClass", - }; - - data = new ArrayList<Pair<String, Double>>(); - - for (int i = 0; i < classes.length; i++) { - data.add(new Pair<String, Double>(classes[i], new Double(i))); - } - - root = new TreeMapNode(SOME_ROOT_LABEL, SOME_ROOT_WEIGHT); - } - - @Test - public void testConvertToTreeMap() { - AbstractTreeAssembler<ArrayList<Pair<String, Double>>> assembler = - new AbstractTreeAssembler<ArrayList<Pair<String, Double>>>() { - - @Override - public void buildTree(ArrayList<Pair<String, Double>> data, TreeMapNode root) { - for (Pair<String, Double> element: data) { - TreeMapNode lastProcessed = processRecord(element.getFirst(), SPLIT_TOKEN, root); - lastProcessed.setRealWeight(element.getSecond()); - } - } - }; - TreeMapNode tree = TreeConverter.convertToTreeMap(data, assembler); - - List<TreeMapNode> nodes = tree.getChildren(); - assertEquals(5, nodes.size()); - - TreeMapNode node = AbstractTreeAssembler.searchNode(nodes, "com"); - assertNotNull(node); - - List<TreeMapNode> nodesFromCom = node.getChildren(); - - // example1 and example2 - assertEquals(2, nodesFromCom.size()); - node = AbstractTreeAssembler.searchNode(nodesFromCom, "example1"); - assertNotNull(node); - - // package2.Class3 and package1 - assertEquals(2, node.getChildren().size()); - - node = AbstractTreeAssembler.searchNode(node.getChildren(), "package2.Class3"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - node = AbstractTreeAssembler.searchNode(nodes, "java.lang.Object"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - node = AbstractTreeAssembler.searchNode(nodes, "example2.package1.Class1"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - // now on to the "repeat1.repeat1.RepeatClass" bunch - node = AbstractTreeAssembler.searchNode(nodes, "repeat1.repeat1.RepeatClass"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - node = AbstractTreeAssembler.searchNode(nodes, "repeat2"); - assertNotNull(node); - assertEquals(2, node.getChildren().size()); - - List<TreeMapNode> nodesFromRepeat2 = node.getChildren(); - node = AbstractTreeAssembler.searchNode(nodesFromRepeat2, "repeat2A.RepeatClass"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - node = AbstractTreeAssembler.searchNode(nodesFromRepeat2, "repeat2B.RepeatClass"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - } - - @Test - public void testFillWeights() { - assertEquals(SOME_ROOT_WEIGHT, TreeConverter.fillWeights(root), DELTA); - TreeMapNode parent = new TreeMapNode("childA", SOME_WEIGHT); - root.addChild(parent); - - final double weightAA = 5.0; - final double weightAB = 10.0; - parent.addChild(new TreeMapNode("childAA", weightAA)); - parent.addChild(new TreeMapNode("childAB", weightAB)); - - assertEquals(SOME_ROOT_WEIGHT, root.getRealWeight(), DELTA); - TreeConverter.fillWeights(root); - assertEquals(weightAA + weightAB, root.getRealWeight(), DELTA); - - List<TreeMapNode> children = parent.getChildren(); - - TreeMapNode child = AbstractTreeAssembler.searchNode(children, "childAA"); - assertNotNull(child); - assertEquals(weightAA, child.getRealWeight(), DELTA); - - child = AbstractTreeAssembler.searchNode(children, "childAB"); - assertNotNull(child); - assertEquals(weightAB, child.getRealWeight(), DELTA); - } - - @Test - public void testPackTree() { - TreeMapNode child = new TreeMapNode("childA", SOME_WEIGHT); - root.addChild(child); - child.addChild(new TreeMapNode("childAA", SOME_WEIGHT)); - child.addChild(new TreeMapNode("childAB", SOME_WEIGHT)); - child = new TreeMapNode("childB", SOME_WEIGHT); - root.addChild(child); - TreeMapNode grandchild = new TreeMapNode("childBA", SOME_WEIGHT); - child.addChild(grandchild); - grandchild.addChild(new TreeMapNode("childBAA", SOME_WEIGHT)); - - TreeConverter.packTree(root); - - assertEquals(0, child.getChildren().size()); - assertEquals("childB.childBA.childBAA", child.getLabel()); - - child = AbstractTreeAssembler.searchNode(root.getChildren(), "childA"); - assertNotNull(child); - assertNotNull(AbstractTreeAssembler.searchNode(child.getChildren(), "childAA")); - assertNotNull(AbstractTreeAssembler.searchNode(child.getChildren(), "childAB")); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/TreeMapTest.java Wed Jun 29 12:23:11 2016 -0400 @@ -0,0 +1,213 @@ +/* + * Copyright 2012-2015 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.swing.components.experimental; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.Pair; + +public class TreeMapTest { + + final private String SOME_ROOT_LABEL = "root"; + final private double SOME_ROOT_WEIGHT = 25.0; + final private double DELTA = 0.01; + final private double SOME_WEIGHT = 3.14; + + private ArrayList<Pair<String, Double>> data; + private TreeMapNode root; + + @Before + public void setUp() { + /* + * This is a tree visualization of the data (weights in parentheses). + * + * ___________root(25)__________ + * / \ + * ________com_______ java + * / \ | + * __example1__ example2 lang + * / \ | | + * Class1(0) Class2(1) Class1(2) Object(3) + * + */ + + final String[] classes = { + "com.example1.Class1", + "com.example1.Class2", + "com.example2.Class1", + "java.lang.Object", + }; + + data = new ArrayList<Pair<String, Double>>(); + + for (int i = 0; i < classes.length; i++) { + data.add(new Pair<String, Double>(classes[i], new Double(i))); + } + + root = new TreeMapNode(SOME_ROOT_LABEL, SOME_ROOT_WEIGHT); + } + + @Test + public void testCreateTreeMap() { + /* + * This is the expected resulting tree (weights in parentheses). + * + * ___________root(6)___________ + * / \ + * ______com(3)______ java.lang.Object(3) + * / \ + * _example1(1)_ example2.Class1(2) + * / \ + * Class1(0) Class2(1) + * + */ + + NodeDataExtractor<ArrayList<Pair<String, Double>>, Pair<String, Double>> extractor = + new NodeDataExtractor<ArrayList<Pair<String, Double>>, Pair<String, Double>>() { + + @Override + public String getNodeSeparator() { + return "."; + } + + @Override + public String getKey(Pair<String, Double> element) { + return element.getFirst(); + } + + @Override + public double getWeight(Pair<String, Double> element) { + return element.getSecond(); + } + + @Override + public Collection<Pair<String, Double>> getAsCollection( + ArrayList<Pair<String, Double>> data) { + return data; + } + }; + TreeMap<ArrayList<Pair<String, Double>>, Pair<String, Double>> treeMap = new TreeMap<>(data, extractor); + + assertEquals(6.0, treeMap.getRoot().getRealWeight(), DELTA); + assertEquals(2, treeMap.getRoot().getChildren().size()); + + TreeMapNode javaLangObjectNode = TreeMap.searchNode(treeMap.getRoot(), "java.lang.Object"); + assertNotNull(javaLangObjectNode); + assertEquals(3.0, javaLangObjectNode.getRealWeight(), DELTA); + assertTrue(javaLangObjectNode.getChildren().isEmpty()); + + TreeMapNode comNode = TreeMap.searchNode(treeMap.getRoot(), "com"); + assertNotNull(comNode); + assertEquals(3.0, comNode.getRealWeight(), DELTA); + assertEquals(2, comNode.getChildren().size()); + + TreeMapNode example2Class1Node = TreeMap.searchNode(comNode, "example2.Class1"); + assertNotNull(example2Class1Node); + assertEquals(2.0, example2Class1Node.getRealWeight(), DELTA); + assertTrue(example2Class1Node.getChildren().isEmpty()); + + TreeMapNode example1Node = TreeMap.searchNode(comNode, "example1"); + assertNotNull(example1Node); + assertEquals(1.0, example1Node.getRealWeight(), DELTA); + assertEquals(2, example1Node.getChildren().size()); + + TreeMapNode class1Node = TreeMap.searchNode(example1Node, "Class1"); + assertNotNull(class1Node); + assertEquals(0.0, class1Node.getRealWeight(), DELTA); + assertTrue(class1Node.getChildren().isEmpty()); + + TreeMapNode class2Node = TreeMap.searchNode(example1Node, "Class2"); + assertNotNull(class2Node); + assertEquals(1.0, class2Node.getRealWeight(), DELTA); + assertTrue(class2Node.getChildren().isEmpty()); + } + + @Test + public void testFillWeights() { + assertEquals(SOME_ROOT_WEIGHT, TreeMap.fillWeights(root), DELTA); + TreeMapNode parent = new TreeMapNode("childA", SOME_WEIGHT); + root.addChild(parent); + + final double weightAA = 5.0; + final double weightAB = 10.0; + parent.addChild(new TreeMapNode("childAA", weightAA)); + parent.addChild(new TreeMapNode("childAB", weightAB)); + + assertEquals(SOME_ROOT_WEIGHT, root.getRealWeight(), DELTA); + TreeMap.fillWeights(root); + assertEquals(weightAA + weightAB, root.getRealWeight(), DELTA); + + TreeMapNode childAANode = TreeMap.searchNode(parent, "childAA"); + assertNotNull(childAANode); + assertEquals(weightAA, childAANode.getRealWeight(), DELTA); + + TreeMapNode childABNode = TreeMap.searchNode(parent, "childAB"); + assertNotNull(childABNode); + assertEquals(weightAB, childABNode.getRealWeight(), DELTA); + } + + @Test + public void testPackTree() { + TreeMapNode child = new TreeMapNode("childA", SOME_WEIGHT); + root.addChild(child); + child.addChild(new TreeMapNode("childAA", SOME_WEIGHT)); + child.addChild(new TreeMapNode("childAB", SOME_WEIGHT)); + child = new TreeMapNode("childB", SOME_WEIGHT); + root.addChild(child); + TreeMapNode grandchild = new TreeMapNode("childBA", SOME_WEIGHT); + child.addChild(grandchild); + grandchild.addChild(new TreeMapNode("childBAA", SOME_WEIGHT)); + + TreeMap.packTree(root); + + assertEquals(0, child.getChildren().size()); + assertEquals("childB.childBA.childBAA", child.getLabel()); + + child = TreeMap.searchNode(root, "childA"); + assertNotNull(child); + assertNotNull(TreeMap.searchNode(child, "childAA")); + assertNotNull(TreeMap.searchNode(child, "childAB")); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectHistogramNodeDataExtractor.java Wed Jun 29 12:23:11 2016 -0400 @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2015 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.vm.heap.analysis.client.swing.internal; + +import java.util.Collection; + +import com.redhat.thermostat.client.swing.components.experimental.NodeDataExtractor; +import com.redhat.thermostat.common.utils.DescriptorConverter; +import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord; +import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram; + +public class ObjectHistogramNodeDataExtractor implements NodeDataExtractor<ObjectHistogram, HistogramRecord> { + + @Override + public String getNodeSeparator() { + return "."; + } + + @Override + public String getKey(HistogramRecord record) { + String className = record.getClassname(); + // if className is a primitive type it is converted with its full name + return DescriptorConverter.toJavaType(className); + } + + @Override + public double getWeight(HistogramRecord record) { + return record.getTotalSize(); + } + + @Override + public Collection<HistogramRecord> getAsCollection(ObjectHistogram histogram) { + return histogram.getHistogram(); + } +}
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectHistogramTreeAssembler.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright 2012-2015 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.vm.heap.analysis.client.swing.internal; - -import com.redhat.thermostat.client.swing.components.experimental.AbstractTreeAssembler; -import com.redhat.thermostat.client.swing.components.experimental.TreeMapNode; -import com.redhat.thermostat.common.utils.DescriptorConverter; -import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord; -import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram; - -public class ObjectHistogramTreeAssembler extends AbstractTreeAssembler<ObjectHistogram> { - - /** - * Key used to put into nodes the <i>number of instances</i> information - * stored in histogram records. - */ - private static final String NUMBER_OF = "Number Of Instances"; - - @Override - public void buildTree(ObjectHistogram histogram, TreeMapNode root) { - for (HistogramRecord record : histogram.getHistogram()) { - String className = record.getClassname(); - - // if className is a primitive type it is converted with its full name - className = DescriptorConverter.toJavaType(className); - TreeMapNode lastProcessed = processRecord(className, ".", root); - - // at this point lastProcessed references to a leaf - lastProcessed.setRealWeight(record.getTotalSize()); - lastProcessed.addInfo(NUMBER_OF, Long.toString(record.getNumberOf())); - } - } -}
--- a/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapTreeMapView.java Wed Jun 29 12:23:11 2016 -0400 +++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapTreeMapView.java Wed Jun 29 12:23:11 2016 -0400 @@ -43,12 +43,13 @@ import javax.swing.SwingUtilities; import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.components.experimental.TreeConverter; +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.common.Size; import com.redhat.thermostat.vm.heap.analysis.client.core.HeapTreeMapView; +import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord; import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram; public class SwingHeapTreeMapView extends HeapTreeMapView implements SwingComponent { @@ -69,8 +70,8 @@ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - TreeMapNode model = TreeConverter.convertToTreeMap( - histogram, new ObjectHistogramTreeAssembler()); + TreeMap<ObjectHistogram, HistogramRecord> map = new TreeMap<>(histogram, new ObjectHistogramNodeDataExtractor()); + TreeMapNode model = map.getRoot(); treeMap.setModel(model); panel.removeAll(); panel.add(treeMap, BorderLayout.CENTER);
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectHistogramTreeAssemblerTest.java Wed Jun 29 12:23:11 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * Copyright 2012-2015 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.vm.heap.analysis.client.swing.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.client.swing.components.experimental.AbstractTreeAssembler; -import com.redhat.thermostat.client.swing.components.experimental.TreeMapNode; -import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram; -import com.sun.tools.hat.internal.model.JavaClass; -import com.sun.tools.hat.internal.model.JavaHeapObject; - -public class ObjectHistogramTreeAssemblerTest { - - private final String ROOT_LABEL = "root"; - private final double ROOT_WEIGHT = 10.0; - - private ObjectHistogram histogram; - private TreeMapNode root; - - @Before - public void setup() { - - final String[] classes = { - "com.example1.Class1", - "com.example1.Class2", - "com.example2", - "java.lang.Object", - }; - - histogram = new ObjectHistogram(); - for (int i = 0; i < classes.length; i++) { - final String className = classes[i]; - - histogram.addThing(new JavaHeapObject() { - public int getSize() { - return 0; - } - - public long getId() { - return 0; - } - - public JavaClass getClazz() { - return new JavaClass(className, 0, 0, 0, 0, null, null, 0); - } - }); - } - - root = new TreeMapNode(ROOT_LABEL, ROOT_WEIGHT); - } - - @Test - public void testBuildTree() { - /* - * This is a visualization of the expected resulting tree. - * - * _____________root____________ - * / \ - * ________com_______ java - * / \ | - * __example1__ example2 lang - * / \ | - * Class1 Class2 Object - * - */ - - ObjectHistogramTreeAssembler assembler = new ObjectHistogramTreeAssembler(); - assembler.buildTree(histogram, root); - - List<TreeMapNode> children = root.getChildren(); - assertEquals(2, children.size()); - - TreeMapNode node = AbstractTreeAssembler.searchNode(children, "java"); - assertNotNull(node); - children = node.getChildren(); - assertEquals(1, children.size()); - node = AbstractTreeAssembler.searchNode(children, "lang"); - assertNotNull(node); - children = node.getChildren(); - assertEquals(1, children.size()); - node = AbstractTreeAssembler.searchNode(children, "Object"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - children = root.getChildren(); - node = AbstractTreeAssembler.searchNode(children, "com"); - assertNotNull(node); - children = node.getChildren(); - assertEquals(2, children.size()); - - node = AbstractTreeAssembler.searchNode(children, "example2"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - node = AbstractTreeAssembler.searchNode(root.getChildren(), "com"); - assertNotNull(node); - node = AbstractTreeAssembler.searchNode(node.getChildren(), "example1"); - assertNotNull(node); - children = node.getChildren(); - assertEquals(2, children.size()); - - node = AbstractTreeAssembler.searchNode(children, "Class1"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - - node = AbstractTreeAssembler.searchNode(children, "Class2"); - assertNotNull(node); - assertTrue(node.getChildren().isEmpty()); - } - -}