diff options
| author | Albert Pham <the.sk89q@gmail.com> | 2013-06-13 15:55:12 -0700 |
|---|---|---|
| committer | Albert Pham <the.sk89q@gmail.com> | 2013-06-13 15:55:12 -0700 |
| commit | 280ad8b8bf2942f055daf5fb6f8ae55a7f88243a (patch) | |
| tree | 05b6fa56f6b826242f6a42f1f8fb2514e3d568d9 | |
| download | spark-280ad8b8bf2942f055daf5fb6f8ae55a7f88243a.tar.gz spark-280ad8b8bf2942f055daf5fb6f8ae55a7f88243a.tar.bz2 spark-280ad8b8bf2942f055daf5fb6f8ae55a7f88243a.zip | |
Initial commit.
| -rw-r--r-- | .gitignore | 32 | ||||
| -rw-r--r-- | README.md | 77 | ||||
| -rw-r--r-- | pom.xml | 145 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/ClassMapping.java | 67 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/DataViewServlet.java | 76 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/McpMapping.java | 112 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/RoastOptions.java | 49 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/StackNode.java | 162 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/StackTraceNode.java | 96 | ||||
| -rw-r--r-- | src/main/java/com/sk89q/warmroast/WarmRoast.java | 309 | ||||
| -rw-r--r-- | src/main/resources/www/index.html | 13 | ||||
| -rw-r--r-- | src/main/resources/www/style.css | 166 | ||||
| -rw-r--r-- | src/main/resources/www/warmroast.js | 43 |
13 files changed, 1347 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82db09d --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Eclipse stuff +/.classpath +/.project +/.settings + +# netbeans +/nbproject + +# we use maven! +/build.xml + +# maven +/target + +# vim +.*.sw[a-p] + +# various other potential build files +/build +/bin +/dist +/manifest.mf +/dependency-reduced-pom.xml + +# Mac filesystem dust +/.DS_Store + +# intellij +*.iml +*.ipr +*.iws +.idea/
\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8edd13 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +WarmRoast +========= + +WarmRoast is an easy-to-use CPU sampling tool for JVM applications, but particularly suited for Minecraft servers/clients. + +* Adjustable sampling frequency. +* Supports loading MCP mappings for deobfuscating class and method names. +* Web-based — perform the profiling on a remote server and view the results in your browser. + * Collapse and expand nodes to see details. + * Easily view CPU usage per method at a glance. + * Hover to highlight all child methods as a group. + * See the percentage of CPU time for each method relative to its parent methods. + * Maintains style and function with use of "File -> Save As" (in tested browsers). + +**Download Latest Version:** http://builds.enginehub.org/job/warmroast/last-successful/ + +Java 7 and above is required to use WarmRoast. + +Screenshots +----------- + + + +Usage +----- + +1. Note the path of your JDK. + +2. Download WarmRoast as `warmroast.jar`. + +3. Replace `/path/to/jdk` in the following command line with the path to your JDK and execute the program. + +### Linux ### + + java -Djava.library.path=/path/to/jdk/jre/bin -cp /path/to/jdk/lib/tools.jar:warmroast.jar com.sk89q.warmroast.WarmRoast + +### Windows ### + + java -Djava.library.path=/path/to/jdk/jre/bin -cp /path/to/jdk/lib/tools.jar;warmroast.jar com.sk89q.warmroast.WarmRoast + +Parameters +---------- + + warmroast.WarmRoast --help + Usage: warmroast [options] + Options: + --bind + The address to bind the HTTP server to + Default: 0.0.0.0 + -h, --help + + Default: false + --interval + The sample rate, in milliseconds + Default: 100 + -m, --mappings + A directory with joined.srg and methods.csv + --name + The name of the VM to attach to + --pid + The PID of the VM to attach to + -p, --port + The port to bind the HTTP server to + Default: 23000 + -t, --thread + Optionally specify a thread to log only + +Hint: `--thread "Server thread"` is useful for Minecraft servers. + +License +------- + +The launcher is licensed under the GNU General Public License, version 3. + +Contributions by third parties must be dual licensed under the two licenses +described within LICENSE.txt (GNU General Public License, version 3, and the +3-clause BSD license). @@ -0,0 +1,145 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>com.sk89q</groupId> + <artifactId>warmroast</artifactId> + <version>1.0.0-SNAPSHOT</version> + <name>WarmRoast</name> + <url>http://www.sk89q.com</url> + <scm> + <connection>scm:git:git://github.com/sk89q/warmroast.git</connection> + <url>https://github.com/sk89q/warmroast</url> + <developerConnection>scm:git:git@github.com:sk89q/warmroast.git</developerConnection> + </scm> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>9.0.3.v20130506</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> + <dependency> + <groupId>net.sf.opencsv</groupId> + <artifactId>opencsv</artifactId> + <version>2.0</version> + </dependency> + <dependency> + <groupId>com.beust</groupId> + <artifactId>jcommander</artifactId> + <version>1.30</version> + </dependency> + </dependencies> + <build> + <resources> + <resource> + <targetPath>www</targetPath> + <filtering>false</filtering> + <directory>${basedir}/src/main/resources/www</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.0</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <mainClass>com.sk89q.warmroast.WarmRoast</mainClass> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>2.1</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <filters> + <filter> + <artifact>*:*</artifact> + <excludes> + <exclude>META-INF/*.SF</exclude> + <exclude>META-INF/*.DSA</exclude> + <exclude>META-INF/*.RSA</exclude> + </excludes> + </filter> + </filters> + <artifactSet> + <excludes> + <exclude>com.sun:tools</exclude> + </excludes> + </artifactSet> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + <profiles> + <profile> + <id>tools-default</id> + <activation> + <activeByDefault>true</activeByDefault> + <file> + <exists>${java.home}/../lib/tools.jar</exists> + </file> + </activation> + <properties> + <toolsJar>${java.home}/../lib/tools.jar</toolsJar> + </properties> + <dependencies> + <dependency> + <groupId>com.sun</groupId> + <artifactId>tools</artifactId> + <version>1.6.0</version> + <scope>system</scope> + <systemPath>${toolsJar}</systemPath> + </dependency> + </dependencies> + </profile> + <profile> + <id>tools-mac</id> + <activation> + <activeByDefault>false</activeByDefault> + <file> + <exists>${java.home}/../Classes/classes.jar</exists> + </file> + </activation> + <properties> + <toolsJar>${java.home}/../Classes/classes.jar</toolsJar> + </properties> + <dependencies> + <dependency> + <groupId>com.sun</groupId> + <artifactId>tools</artifactId> + <version>1.6.0</version> + <scope>system</scope> + <systemPath>${toolsJar}</systemPath> + </dependency> + </dependencies> + </profile> + </profiles> +</project>
\ No newline at end of file diff --git a/src/main/java/com/sk89q/warmroast/ClassMapping.java b/src/main/java/com/sk89q/warmroast/ClassMapping.java new file mode 100644 index 0000000..ad3f7c0 --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/ClassMapping.java @@ -0,0 +1,67 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package com.sk89q.warmroast; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ClassMapping { + + private final String obfuscated; + private final String actual; + private final Map<String, List<String>> methods = new HashMap<>(); + + public ClassMapping(String obfuscated, String actual) { + this.obfuscated = obfuscated; + this.actual = actual; + } + + public String getObfuscated() { + return obfuscated; + } + + public String getActual() { + return actual; + } + + public void addMethod(String obfuscated, String actual) { + List<String> m = methods.get(obfuscated); + if (m == null) { + m = new ArrayList<>(); + methods.put(obfuscated, m); + } + m.add(actual); + } + + public List<String> mapMethod(String obfuscated) { + List<String> m = methods.get(obfuscated); + if (m == null) { + return new ArrayList<>(); + } + return m; + } + + @Override + public String toString() { + return getObfuscated() + "->" + getActual(); + } + +} diff --git a/src/main/java/com/sk89q/warmroast/DataViewServlet.java b/src/main/java/com/sk89q/warmroast/DataViewServlet.java new file mode 100644 index 0000000..205dd3e --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/DataViewServlet.java @@ -0,0 +1,76 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package com.sk89q.warmroast; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collection; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class DataViewServlet extends HttpServlet { + + private static final long serialVersionUID = -2331397310804298286L; + + private final WarmRoast roast; + + public DataViewServlet(WarmRoast roast) { + this.roast = roast; + } + + @Override + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html; charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + PrintWriter w = response.getWriter(); + w.println("<!DOCTYPE html><html><head><title>WarmRoast</title>"); + w.println("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">"); + w.println("</head><body>"); + w.println("<h1>WarmRoast</h1>"); + w.println("<div class=\"loading\">Downloading snapshot; please wait...</div>"); + w.println("<div class=\"stack\" style=\"display: none\">"); + synchronized (roast) { + Collection<StackNode> nodes = roast.getData().values(); + for (StackNode node : nodes) { + w.println(node.toHtml(roast.getMapping())); + } + if (nodes.size() == 0) { + w.println("<p class=\"no-results\">There are no results. " + + "(Thread filter does not match thread?)</p>"); + } + } + w.println("</div>"); + w.println("<p class=\"legend\">Legend: "); + w.println("<span class=\"matched\">Mapped</span> "); + w.println("<span class=\"multiple-matches\">Multiple Mappings</span> "); + w.println("</p>"); + w.println("<div id=\"overlay\"></div>"); + w.println("<p class=\"footer\">"); + w.println("Icons from <a href=\"http://www.fatcow.com/\">FatCow</a> — "); + w.println("<a href=\"http://github.com/sk89q/warmroast\">github.com/sk89q/warmroast</a></p>"); + w.println("<script src=\"//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js\"></script>"); + w.println("<script src=\"warmroast.js\"></script>"); + w.println("</body></html>"); + } +}
\ No newline at end of file diff --git a/src/main/java/com/sk89q/warmroast/McpMapping.java b/src/main/java/com/sk89q/warmroast/McpMapping.java new file mode 100644 index 0000000..5ef2ff9 --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/McpMapping.java @@ -0,0 +1,112 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package com.sk89q.warmroast; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.FileUtils; + +import au.com.bytecode.opencsv.CSVReader; + +public class McpMapping { + + private static final Pattern clPattern = + Pattern.compile("CL: (?<obfuscated>[^ ]+) (?<actual>[^ ]+)"); + private static final Pattern mdPattern = + Pattern.compile("MD: (?<obfuscatedClass>[^ /]+)/(?<obfuscatedMethod>[^ ]+) " + + "[^ ]+ (?<method>[^ ]+) [^ ]+"); + + private final Map<String, ClassMapping> classes = new HashMap<>(); + private final Map<String, String> methods = new HashMap<>(); + + public ClassMapping mapClass(String obfuscated) { + return classes.get(obfuscated); + } + + public void read(File joinedFile, File methodsFile) throws IOException { + try (FileReader r = new FileReader(methodsFile)) { + try (CSVReader reader = new CSVReader(r)) { + List<String[]> entries = reader.readAll(); + processMethodNames(entries); + } + } + + List<String> lines = FileUtils.readLines(joinedFile, "UTF-8"); + processClasses(lines); + processMethods(lines); + } + + public String fromMethodId(String id) { + String method = methods.get(id); + if (method == null) { + return id; + } + return method; + } + + private void processMethodNames(List<String[]> entries) { + boolean first = true; + for (String[] entry : entries) { + if (entry.length < 2) { + continue; + } + if (first) { // Header + first = false; + continue; + } + methods.put(entry[0], entry[1]); + } + } + + private void processClasses(List<String> lines) { + for (String line : lines) { + Matcher m = clPattern.matcher(line); + if (m.matches()) { + String obfuscated = m.group("obfuscated"); + String actual = m.group("actual").replace("/", "."); + classes.put(obfuscated, new ClassMapping(obfuscated, actual)); + } + } + } + + private void processMethods(List<String> lines) { + for (String line : lines) { + Matcher m = mdPattern.matcher(line); + if (m.matches()) { + String obfuscatedClass = m.group("obfuscatedClass"); + String obfuscatedMethod = m.group("obfuscatedMethod"); + String method = m.group("method"); + String methodId = method.substring(method.lastIndexOf('/') + 1); + ClassMapping mapping = mapClass(obfuscatedClass); + if (mapping != null) { + mapping.addMethod(obfuscatedMethod, + fromMethodId(methodId)); + } + } + } + } + +} diff --git a/src/main/java/com/sk89q/warmroast/RoastOptions.java b/src/main/java/com/sk89q/warmroast/RoastOptions.java new file mode 100644 index 0000000..edb6a0e --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/RoastOptions.java @@ -0,0 +1,49 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package com.sk89q.warmroast; + +import com.beust.jcommander.Parameter; + +public class RoastOptions { + + @Parameter(names = { "-h", "--help" }, help = true) + public boolean help; + + @Parameter(names = { "--bind" }, description = "The address to bind the HTTP server to") + public String bindAddress = "0.0.0.0"; + + @Parameter(names = { "-p", "--port" }, description = "The port to bind the HTTP server to") + public Integer port = 23000; + + @Parameter(names = { "--pid" }, description = "The PID of the VM to attach to") + public Integer pid; + + @Parameter(names = { "--name" }, description = "The name of the VM to attach to") + public String vmName; + + @Parameter(names = { "-t", "--thread" }, description = "Optionally specify a thread to log only") + public String threadName; + + @Parameter(names = { "-m", "--mappings" }, description = "A directory with joined.srg and methods.csv") + public String mappingsDir; + + @Parameter(names = { "--interval" }, description = "The sample rate, in milliseconds") + public Integer interval = 100; + +} diff --git a/src/main/java/com/sk89q/warmroast/StackNode.java b/src/main/java/com/sk89q/warmroast/StackNode.java new file mode 100644 index 0000000..216ca5f --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/StackNode.java @@ -0,0 +1,162 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package com.sk89q.warmroast; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class StackNode implements Comparable<StackNode> { + + private final String name; + private final Map<String, StackNode> children = new HashMap<>(); + private long totalTime; + + public StackNode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getNameHtml(McpMapping mapping) { + return escapeHtml(getName()); + } + + public Collection<StackNode> getChildren() { + List<StackNode> list = new ArrayList<>(children.values()); + Collections.sort(list); + return list; + } + + public StackNode getChild(String name) { + StackNode child = children.get(name); + if (child == null) { + child = new StackNode(name); + children.put(name, child); + } + return child; + } + + public StackNode getChild(String className, String methodName) { + StackTraceNode node = new StackTraceNode(className, methodName); + StackNode child = children.get(node.getName()); + if (child == null) { + child = node; + children.put(node.getName(), node); + } + return child; + } + + public long getTotalTime() { + return totalTime; + } + + public void log(long time) { + totalTime += time; + } + + private void log(StackTraceElement[] elements, int skip, long time) { + log(time); + + if (elements.length - skip == 0) { + return; + } + + StackTraceElement bottom = elements[elements.length - (skip + 1)]; + getChild(bottom.getClassName(), bottom.getMethodName()) + .log(elements, skip + 1, time); + } + + public void log(StackTraceElement[] elements, long time) { + log(elements, 0, time); + } + + @Override + public int compareTo(StackNode o) { + return getName().compareTo(o.getName()); + } + + private void writeHtml(StringBuilder builder, McpMapping mapping, long totalTime) { + builder.append("<div class=\"node collapsed\">"); + builder.append("<div class=\"name\">"); + builder.append(getNameHtml(mapping)); + builder.append("<span class=\"percent\">"); + builder + .append(String.format("%.2f", getTotalTime() / (double) totalTime * 100)) + .append("%"); + builder.append("</span>"); + builder.append("<span class=\"time\">"); + builder.append(getTotalTime()).append("ms"); + builder.append("</span>"); + builder.append("<span class=\"bar\">"); + builder.append("<span class=\"bar-inner\" style=\"width:") + .append(String.format("%.2f", getTotalTime() / (double) totalTime * 100)) + .append("%\">"); + builder.append("</span>"); + builder.append("</span>"); + builder.append("</div>"); + builder.append("<ul class=\"children\">"); + for (StackNode child : getChildren()) { + builder.append("<li>"); + child.writeHtml(builder, mapping, totalTime); + builder.append("</li>"); + } + builder.append("</ul>"); + builder.append("</div>"); + } + + public String toHtml(McpMapping mapping) { + StringBuilder builder = new StringBuilder(); + writeHtml(builder, mapping, getTotalTime()); + return builder.toString(); + } + + private void writeString(StringBuilder builder, int indent) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < indent; i++) { + b.append(" "); + } + String padding = b.toString(); + + for (StackNode child : getChildren()) { + builder.append(padding).append(child.getName()); + builder.append(" "); + builder.append(getTotalTime()).append("ms"); + builder.append("\n"); + child.writeString(builder, indent + 1); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + writeString(builder, 0); + return builder.toString(); + } + + protected static String escapeHtml(String str) { + return str.replace("&", "&").replace("<", "<").replace(">", ">"); + } + +} diff --git a/src/main/java/com/sk89q/warmroast/StackTraceNode.java b/src/main/java/com/sk89q/warmroast/StackTraceNode.java new file mode 100644 index 0000000..1857cd1 --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/StackTraceNode.java @@ -0,0 +1,96 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package com.sk89q.warmroast; + +import java.util.List; + +public class StackTraceNode extends StackNode { + + private final String className; + private final String methodName; + + public StackTraceNode(String className, String methodName) { + super(className + "." + methodName + "()"); + this.className = className; + this.methodName = methodName; + } + + public String getClassName() { + return className; + } + + public String getMethodName() { + return methodName; + } + + @Override + public String getNameHtml(McpMapping mapping) { + ClassMapping classMapping = mapping.mapClass(getClassName()); + if (classMapping != null) { + String className = "<span class=\"matched\" title=\"" + + escapeHtml(getClassName()) + "\">" + + escapeHtml(classMapping.getActual()) + "</span>"; + + List<String> actualMethods = classMapping.mapMethod(getMethodName()); + if (actualMethods.size() == 0) { + return className + "." + escapeHtml(getMethodName()) + "()"; + } else if (actualMethods.size() == 1) { + return className + + ".<span class=\"matched\" title=\"" + + escapeHtml(getMethodName()) + "\">" + + escapeHtml(actualMethods.get(0)) + "</span>()"; + } else { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for (String m : actualMethods) { + if (!first) { + builder.append(" "); + } + builder.append(m); + first = false; + } + return className + + ".<span class=\"multiple-matches\" title=\"" + + builder.toString() + "\">" + escapeHtml(getMethodName()) + "</span>()"; + } + } else { + String actualMethod = mapping.fromMethodId(getMethodName()); + if (actualMethod == null) { + return escapeHtml(getClassName()) + "." + escapeHtml(getMethodName()) + "()"; + } else { + return className + + ".<span class=\"matched\" title=\"" + + escapeHtml(getMethodName()) + "\">" + + escapeHtml(actualMethod) + "</span>()"; + } + } + } + + @Override + public int compareTo(StackNode o) { + if (getTotalTime() == o.getTotalTime()) { + return 0; + } else if (getTotalTime()> o.getTotalTime()) { + return -1; + } else { + return 1; + } + } + +} diff --git a/src/main/java/com/sk89q/warmroast/WarmRoast.java b/src/main/java/com/sk89q/warmroast/WarmRoast.java new file mode 100644 index 0000000..6ddd9ca --- /dev/null +++ b/src/main/java/com/sk89q/warmroast/WarmRoast.java @@ -0,0 +1,309 @@ +/* + * WarmRoast + * Copyright (C) 2013 Albert Pham <http://www.sk89q.com> + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package com.sk89q.warmroast; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeMap; + +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.server.handler.ResourceHandler; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import com.beust.jcommander.JCommander; +import com.sun.tools.attach.AgentInitializationException; +import com.sun.tools.attach.AgentLoadException; +imp |
