Mercurial > hg > release > thermostat-1.2
changeset 1564:6a6dbf86e717
Show percent of time in profiling results
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-November/011678.html
line wrap: on
line diff
--- a/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/LocaleResources.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/LocaleResources.java Mon Nov 24 13:12:49 2014 -0500 @@ -49,6 +49,9 @@ UNKNOWN_COMMAND, INTERRUPTED_WAITING_FOR_RESPONSE, + METHOD_PROFILE_HEADER_PERCENTAGE, + METHOD_PROFILE_HEADER_TIME, + METHOD_PROFILE_HEADER_NAME, ; static final String RESOURCE_BUNDLE = LocaleResources.class.getPackage().getName() + ".strings";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/ProfileResultFormatter.java Mon Nov 24 13:12:49 2014 -0500 @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2014 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.profiler.client.cli.internal; + +import java.io.OutputStream; + +import com.redhat.thermostat.common.cli.TableRenderer; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; + +public class ProfileResultFormatter { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private static final int NUM_COLUMNS = 3; + + private static final String HEADER_PERCENTAGE = translator.localize(LocaleResources.METHOD_PROFILE_HEADER_PERCENTAGE).getContents(); + private static final String HEADER_TIME = translator.localize(LocaleResources.METHOD_PROFILE_HEADER_TIME).getContents(); + private static final String HEADER_NAME = translator.localize(LocaleResources.METHOD_PROFILE_HEADER_NAME).getContents(); + + private TableRenderer renderer = new TableRenderer(NUM_COLUMNS); + + public void addHeader() { + printLine(HEADER_PERCENTAGE, HEADER_TIME, HEADER_NAME); + } + + public void addMethodInfo(MethodInfo methodInfo) { + printLine(String.format("%4f", methodInfo.percentageTime), + String.valueOf(methodInfo.totalTimeInMillis), + methodInfo.name); + } + + public void format(OutputStream output) { + renderer.render(output); + } + + private void printLine(String percentage, String time, String name) { + renderer.printLine(percentage, time, name); + } +}
--- a/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/ProfileVmCommand.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/ProfileVmCommand.java Mon Nov 24 13:12:49 2014 -0500 @@ -36,11 +36,11 @@ package com.redhat.thermostat.vm.profiler.client.cli.internal; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.Semaphore; @@ -53,12 +53,14 @@ import com.redhat.thermostat.common.command.RequestResponseListener; import com.redhat.thermostat.common.command.Response; import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.common.utils.StreamUtils; import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.VmInfoDAO; import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser; import com.redhat.thermostat.vm.profiler.common.ProfileDAO; import com.redhat.thermostat.vm.profiler.common.ProfileRequest; @@ -172,16 +174,31 @@ private void showProfilingResults(Console console, VmRef vm) { ProfileDAO dao = getService(ProfileDAO.class); InputStream data = dao.loadLatestProfileData(vm); - displayProfilingData(console, data); + parseAndDisplayProfilingData(console, data); } - private void displayProfilingData(Console console, InputStream data) { - try { - StreamUtils.copyStream(new BufferedInputStream(data), new BufferedOutputStream(console.getOutput())); - } catch (IOException e) { - console.getError().println("Error displaying data"); - e.printStackTrace(); + private void parseAndDisplayProfilingData(Console console, InputStream data) { + ProfilingResultParser parser = new ProfilingResultParser(); + ProfilingResult results = parser.parse(data); + + List<MethodInfo> methodInfos = new ArrayList<>(results.getMethodInfo()); + + Collections.sort(methodInfos, new Comparator<MethodInfo>() { + @Override + public int compare(MethodInfo o1, MethodInfo o2) { + return Double.compare(o2.percentageTime, o1.percentageTime); + } + }); + + ProfileResultFormatter formatter = new ProfileResultFormatter(); + + formatter.addHeader(); + + for (MethodInfo method : methodInfos) { + formatter.addMethodInfo(method); } + + formatter.format(console.getOutput()); } void setAgentInfoDAO(AgentInfoDAO dao) {
--- a/vm-profiler/client-cli/src/main/resources/com/redhat/thermostat/vm/profiler/client/cli/internal/strings.properties Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-cli/src/main/resources/com/redhat/thermostat/vm/profiler/client/cli/internal/strings.properties Mon Nov 24 13:12:49 2014 -0500 @@ -5,4 +5,8 @@ COMMAND_EXPECTED = A valid subcommand is expected. UNKNOWN_COMMAND = Unknown command: {0} -INTERRUPTED_WAITING_FOR_RESPONSE = Interrupted while waiting for a response from agent \ No newline at end of file +INTERRUPTED_WAITING_FOR_RESPONSE = Interrupted while waiting for a response from agent + +METHOD_PROFILE_HEADER_PERCENTAGE = % Time +METHOD_PROFILE_HEADER_TIME = Time (ms) +METHOD_PROFILE_HEADER_NAME = Method Name
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-cli/src/test/java/com/redhat/thermostat/vm/profiler/client/cli/internal/ProfileResultFormatterTest.java Mon Nov 24 13:12:49 2014 -0500 @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2014 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.profiler.client.cli.internal; + +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; + +public class ProfileResultFormatterTest { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private final String PERCENTAGE = translator.localize(LocaleResources.METHOD_PROFILE_HEADER_PERCENTAGE).getContents(); + private final String TIME = translator.localize(LocaleResources.METHOD_PROFILE_HEADER_TIME).getContents(); + private final String NAME = translator.localize(LocaleResources.METHOD_PROFILE_HEADER_NAME).getContents(); + + private ProfileResultFormatter formatter; + private ByteArrayOutputStream baos; + private PrintStream out; + + @Before + public void setUp() { + formatter = new ProfileResultFormatter(); + baos = new ByteArrayOutputStream(); + out = new PrintStream(baos); + } + + @Test + public void testPrintHeader() { + formatter.addHeader(); + formatter.format(out); + + String output = new String(baos.toByteArray()); + assertTrue(output.contains(PERCENTAGE)); + assertTrue(output.contains(TIME)); + assertTrue(output.contains(NAME)); + } + + @Test + public void testPrintProfileResult() { + String methodName = "Class.method()"; + long time = 1; + double percentage = 100; + + MethodInfo info = new MethodInfo(methodName, time, percentage); + + formatter.addMethodInfo(info); + formatter.format(out); + + String output = new String(baos.toByteArray()); + + assertTrue(output.contains(methodName)); + assertTrue(output.contains(String.valueOf(time))); + assertTrue(output.contains(String.valueOf(percentage))); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-core/src/main/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResult.java Mon Nov 24 13:12:49 2014 -0500 @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2014 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.profiler.client.core; + +import java.util.Collections; +import java.util.List; + +public class ProfilingResult { + + public static class MethodInfo { + + public final String name; + public final long totalTimeInMillis; + public final double percentageTime; + + public MethodInfo(String name, long totalTime, double percentageTime) { + this.name = name; + this.totalTimeInMillis = totalTime; + this.percentageTime = percentageTime; + } + } + + private List<MethodInfo> info; + + public ProfilingResult(List<MethodInfo> data) { + this.info = Collections.unmodifiableList(data); + } + + public List<MethodInfo> getMethodInfo() { + return info; + } +} \ No newline at end of file
--- a/vm-profiler/client-core/src/main/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResultParser.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-core/src/main/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResultParser.java Mon Nov 24 13:12:49 2014 -0500 @@ -41,40 +41,57 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.Collections; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; public class ProfilingResultParser { private static final Logger logger = LoggingUtils.getLogger(ProfilingResultParser.class); - public class ProfilingResult { - /** Method Name -> Time (ns) */ - public final Map<String, Long> time; - public ProfilingResult(Map<String, Long> data) { - this.time = Collections.unmodifiableMap(data); - } + public ProfilingResult parse(InputStream in) { + Map<String, Long> result = readData(in); + return processData(result); } - public ProfilingResult parse(InputStream in) { + private Map<String, Long> readData(InputStream in) { Map<String, Long> result = new HashMap<String, Long>(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { String[] parts = line.split("\\s+"); - long time = Long.valueOf(parts[0]); + long time = TimeUnit.NANOSECONDS.toMillis(Long.valueOf(parts[0])); String name = parts[1]; result.put(name, time); } } catch (IOException e) { logger.log(Level.WARNING, "Unable to parse profiling data: ", e); } - return new ProfilingResult(result); + + return result; } + + private ProfilingResult processData(Map<String, Long> results) { + ArrayList<MethodInfo> info = new ArrayList<>(); + long totalTime = 0; + for (Entry<String, Long> entry : results.entrySet()) { + totalTime += entry.getValue().longValue(); + } + + for (Entry<String, Long> entry : results.entrySet()) { + MethodInfo method = new MethodInfo(entry.getKey(), entry.getValue(), (entry.getValue() * 1.0 / totalTime) * 100); + info.add(method); + } + + return new ProfilingResult(info); + } + }
--- a/vm-profiler/client-core/src/test/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResultParserTest.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-core/src/test/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResultParserTest.java Mon Nov 24 13:12:49 2014 -0500 @@ -40,22 +40,29 @@ import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; -import java.util.Map; +import java.util.List; import org.junit.Test; -import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; public class ProfilingResultParserTest { @Test public void parsesCorrectly() throws Exception { - String data = "1 foo\n2 bar"; + String data = "1000000 foo\n2000000 bar"; ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); - ProfilingResultParser parser = new ProfilingResultParser(); - ProfilingResult result = parser.parse(in); - Map<String, Long> times = result.time; - assertEquals(1, (long) times.get("foo")); - assertEquals(2, (long) times.get("bar")); + + ProfilingResult result = new ProfilingResultParser().parse(in); + + List<MethodInfo> methods = result.getMethodInfo(); + + MethodInfo method0 = methods.get(0); + assertEquals("foo", method0.name); + assertEquals(1, method0.totalTimeInMillis); + + MethodInfo method1 = methods.get(1); + assertEquals("bar", method1.name); + assertEquals(2, method1.totalTimeInMillis); } }
--- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResources.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResources.java Mon Nov 24 13:12:49 2014 -0500 @@ -48,6 +48,7 @@ PROFILER_LIST_ITEM, PROFILER_RESULTS_METHOD, + PROFILER_RESULTS_PERCENTAGE_TIME, PROFILER_RESULTS_TIME, ;
--- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileView.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileView.java Mon Nov 24 13:12:49 2014 -0500 @@ -40,7 +40,6 @@ import java.awt.Component; import java.util.Date; import java.util.List; -import java.util.Map.Entry; import java.util.Vector; import java.util.concurrent.CopyOnWriteArrayList; @@ -64,7 +63,8 @@ import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult.MethodInfo; public class SwingVmProfileView extends VmProfileView implements SwingComponent { @@ -141,10 +141,13 @@ Vector<String> columnNames = new Vector<>(); columnNames.add(translator.localize(LocaleResources.PROFILER_RESULTS_METHOD).getContents()); - columnNames.add(translator.localize(LocaleResources.PROFILER_RESULTS_TIME, "ns").getContents()); + columnNames.add(translator.localize(LocaleResources.PROFILER_RESULTS_PERCENTAGE_TIME).getContents()); + columnNames.add(translator.localize(LocaleResources.PROFILER_RESULTS_TIME, "ms").getContents()); tableModel = new DefaultTableModel(columnNames, 0); JTable profileTable = new JTable(tableModel); + profileTable.setAutoCreateRowSorter(true); + JScrollPane profileTablePane = new JScrollPane(profileTable); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, @@ -213,10 +216,11 @@ // delete all existing data tableModel.setRowCount(0); - for (Entry<String, Long> methodAndTime : results.time.entrySet()) { + for (MethodInfo methodInfo: results.getMethodInfo()) { Object[] data = new Object[] { - methodAndTime.getKey(), - methodAndTime.getValue(), + methodInfo.name, + methodInfo.percentageTime, + methodInfo.totalTimeInMillis, }; tableModel.addRow(data); }
--- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileController.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileController.java Mon Nov 24 13:12:49 2014 -0500 @@ -60,8 +60,8 @@ import com.redhat.thermostat.shared.locale.Translate; import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser; -import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.Profile; import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.ProfileAction; import com.redhat.thermostat.vm.profiler.common.ProfileDAO;
--- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileView.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileView.java Mon Nov 24 13:12:49 2014 -0500 @@ -41,7 +41,7 @@ import com.redhat.thermostat.client.core.views.BasicView; import com.redhat.thermostat.client.core.views.UIComponent; import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; public abstract class VmProfileView extends BasicView implements UIComponent {
--- a/vm-profiler/client-swing/src/main/resources/com/redhat/thermostat/vm/profiler/client/swing/internal/strings.properties Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-swing/src/main/resources/com/redhat/thermostat/vm/profiler/client/swing/internal/strings.properties Mon Nov 24 13:12:49 2014 -0500 @@ -7,4 +7,5 @@ PROFILER_LIST_ITEM = Session @ {1} ({0}) PROFILER_RESULTS_METHOD = Method +PROFILER_RESULTS_PERCENTAGE_TIME = Percentage PROFILER_RESULTS_TIME = Total Time ({0})
--- a/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileControllerTest.java Mon Nov 24 13:12:40 2014 -0500 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileControllerTest.java Mon Nov 24 13:12:49 2014 -0500 @@ -69,7 +69,7 @@ import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResult; import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.Profile; import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.ProfileAction; import com.redhat.thermostat.vm.profiler.common.ProfileDAO;