提交 126fd829 authored 作者: Thomas Mueller's avatar Thomas Mueller

The profiler tool can now process files with full thread dumps.

上级 dd38db03
......@@ -18,11 +18,16 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>MVStore mode: the CLOB and BLOB storage was re-implemented and is
<ul><li>The profiler tool can now process files with full thread dumps.
</li><li>MVStore mode: the CLOB and BLOB storage was re-implemented and is
now much faster than with the PageStore (which is still the default storage).
</li><li>Various bugs in the MVStore storage and have been fixed.
</li><li>MVStore mode: creating indexes is now much faster
(in many cases faster than with the default PageStore).
</li><li>Various bugs in the MVStore storage and have been fixed,
including a bug in the R-tree implementation.
</li><li>The method org.h2.expression.Function.getCost could throw a NullPointException.
</li><li>Storing LOBs in separate files (outside of the database) is no longer supported for new databases.
</li><li>Storing LOBs in separate files (outside of the main database file)
is no longer supported for new databases.
</li><li>Lucene 2 is no longer supported.
</li><li>Fix bug in calculating default MIN and MAX values for SEQUENCE.
</li></ul>
......
......@@ -7,13 +7,16 @@
package org.h2.util;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
......@@ -22,7 +25,7 @@ import java.util.Map;
/**
* A simple CPU profiling tool similar to java -Xrunhprof. It can be used
* in-process (to profile the current application) or as a standalone program
* (to profile a different process).
* (to profile a different process, or files containing full thread dumps).
*/
public class Profiler implements Runnable {
......@@ -37,11 +40,19 @@ public class Profiler implements Runnable {
private int pid;
private final String[] ignoreLines = {};
private final String[] ignoreLines = (
"java," +
"sun," +
"com.sun.," +
"com.google.common.," +
"com.mongodb."
).split(",");
private final String[] ignorePackages = (
"java," +
"sun," +
"com.sun."
"com.sun.," +
"com.google.common.," +
"com.mongodb."
).split(",");
private final String[] ignoreThreads = (
"java.lang.Object.wait," +
......@@ -49,6 +60,7 @@ public class Profiler implements Runnable {
"java.lang.Thread.getThreads," +
"java.lang.Thread.sleep," +
"java.lang.UNIXProcess.waitForProcessExit," +
"java.net.PlainDatagramSocketImpl.receive0," +
"java.net.PlainSocketImpl.accept," +
"java.net.PlainSocketImpl.socketAccept," +
"java.net.SocketInputStream.socketRead," +
......@@ -72,6 +84,7 @@ public class Profiler implements Runnable {
private Thread thread;
private long start;
private long time;
private int threadDumps;
/**
* This method is called when the agent is installed.
......@@ -106,24 +119,50 @@ public class Profiler implements Runnable {
private void run(String... args) {
if (args.length == 0) {
System.out.println("Show profiling data");
System.out.println("Usage: java " + getClass().getName() + " <pid>");
System.out.println("Usage: java " + getClass().getName() + " <pid> | <stackTraceFileNames>");
System.out.println("Processes:");
String processes = exec("jps", "-l");
System.out.println(processes);
return;
}
pid = Integer.parseInt(args[0]);
start = System.currentTimeMillis();
long last = 0;
while (true) {
tick();
long t = System.currentTimeMillis();
if (t - last > 5000) {
time = System.currentTimeMillis() - start;
System.out.println(getTopTraces(3));
last = t;
if (args[0].matches("\\d+")) {
pid = Integer.parseInt(args[0]);
long last = 0;
while (true) {
tick();
long t = System.currentTimeMillis();
if (t - last > 5000) {
time = System.currentTimeMillis() - start;
System.out.println(getTopTraces(3));
last = t;
}
}
}
try {
for (String file : args) {
Reader reader;
LineNumberReader r;
reader = new InputStreamReader(new FileInputStream(file), "CP1252");
r = new LineNumberReader(reader);
while (true) {
String line = r.readLine();
if (line == null) {
break;
} else if (line.startsWith("Full thread dump")) {
threadDumps++;
}
}
reader.close();
reader = new InputStreamReader(new FileInputStream(file), "CP1252");
r = new LineNumberReader(reader);
processList(readStackTrace(r));
reader.close();
}
System.out.println(getTopTraces(3));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static List<Object[]> getRunnableStackTraces() {
......@@ -144,52 +183,56 @@ public class Profiler implements Runnable {
}
private static List<Object[]> readRunnableStackTraces(int pid) {
ArrayList<Object[]> list = new ArrayList<Object[]>();
try {
String jstack = exec("jstack", "" + pid);
LineNumberReader r = new LineNumberReader(new StringReader(jstack));
return readStackTrace(r);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static List<Object[]> readStackTrace(LineNumberReader r) throws IOException {
ArrayList<Object[]> list = new ArrayList<Object[]>();
while (true) {
String line = r.readLine();
if (line == null) {
break;
}
if (!line.startsWith("\"")) {
// not a thread
continue;
}
line = r.readLine();
if (line == null) {
break;
}
line = line.trim();
if (!line.startsWith("java.lang.Thread.State: RUNNABLE")) {
continue;
}
ArrayList<String> stack = new ArrayList<String>();
while (true) {
String line = r.readLine();
if (line == null) {
break;
}
if (!line.startsWith("\"")) {
// not a thread
continue;
}
line = r.readLine();
if (line == null) {
break;
}
line = line.trim();
if (!line.startsWith("java.lang.Thread.State: RUNNABLE")) {
if (line.startsWith("- ")) {
continue;
}
ArrayList<String> stack = new ArrayList<String>();
while (true) {
line = r.readLine();
if (line == null) {
break;
}
line = line.trim();
if (line.startsWith("- ")) {
continue;
}
if (!line.startsWith("at ")) {
break;
}
line = line.substring(3).trim();
stack.add(line);
}
if (stack.size() > 0) {
String[] s = stack.toArray(new String[stack.size()]);
list.add(s);
if (!line.startsWith("at ")) {
break;
}
line = line.substring(3).trim();
stack.add(line);
}
if (stack.size() > 0) {
String[] s = stack.toArray(new String[stack.size()]);
list.add(s);
}
return list;
} catch (IOException e) {
throw new RuntimeException(e);
}
return list;
}
private static String exec(String... args) {
......@@ -292,6 +335,11 @@ public class Profiler implements Runnable {
} else {
list = getRunnableStackTraces();
}
threadDumps++;
processList(list);
}
private void processList(List<Object[]> list) {
for (Object[] dump : list) {
if (startsWithAny(dump[0].toString(), ignoreThreads)) {
continue;
......@@ -377,8 +425,14 @@ public class Profiler implements Runnable {
private String getTopTraces(int count) {
StringBuilder buff = new StringBuilder();
buff.append("Profiler: top ").append(count).append(" stack trace(s) of ").append(time).
append(" ms:").append(LINE_SEPARATOR);
buff.append("Profiler: top ").append(count).append(" stack trace(s) of ");
if (time > 0) {
buff.append(" of ").append(time).append(" ms");
}
if (threadDumps > 0) {
buff.append(" of ").append(threadDumps).append(" thread dumps");
}
buff.append(":").append(LINE_SEPARATOR);
if (counts.size() == 0) {
buff.append("(none)").append(LINE_SEPARATOR);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论