提交 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 ...@@ -18,11 +18,16 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <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). 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>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>Lucene 2 is no longer supported.
</li><li>Fix bug in calculating default MIN and MAX values for SEQUENCE. </li><li>Fix bug in calculating default MIN and MAX values for SEQUENCE.
</li></ul> </li></ul>
......
...@@ -7,13 +7,16 @@ ...@@ -7,13 +7,16 @@
package org.h2.util; package org.h2.util;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader; import java.io.LineNumberReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -22,7 +25,7 @@ import java.util.Map; ...@@ -22,7 +25,7 @@ import java.util.Map;
/** /**
* A simple CPU profiling tool similar to java -Xrunhprof. It can be used * 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 * 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 { public class Profiler implements Runnable {
...@@ -37,11 +40,19 @@ public class Profiler implements Runnable { ...@@ -37,11 +40,19 @@ public class Profiler implements Runnable {
private int pid; 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 = ( private final String[] ignorePackages = (
"java," + "java," +
"sun," + "sun," +
"com.sun." "com.sun.," +
"com.google.common.," +
"com.mongodb."
).split(","); ).split(",");
private final String[] ignoreThreads = ( private final String[] ignoreThreads = (
"java.lang.Object.wait," + "java.lang.Object.wait," +
...@@ -49,6 +60,7 @@ public class Profiler implements Runnable { ...@@ -49,6 +60,7 @@ public class Profiler implements Runnable {
"java.lang.Thread.getThreads," + "java.lang.Thread.getThreads," +
"java.lang.Thread.sleep," + "java.lang.Thread.sleep," +
"java.lang.UNIXProcess.waitForProcessExit," + "java.lang.UNIXProcess.waitForProcessExit," +
"java.net.PlainDatagramSocketImpl.receive0," +
"java.net.PlainSocketImpl.accept," + "java.net.PlainSocketImpl.accept," +
"java.net.PlainSocketImpl.socketAccept," + "java.net.PlainSocketImpl.socketAccept," +
"java.net.SocketInputStream.socketRead," + "java.net.SocketInputStream.socketRead," +
...@@ -72,6 +84,7 @@ public class Profiler implements Runnable { ...@@ -72,6 +84,7 @@ public class Profiler implements Runnable {
private Thread thread; private Thread thread;
private long start; private long start;
private long time; private long time;
private int threadDumps;
/** /**
* This method is called when the agent is installed. * This method is called when the agent is installed.
...@@ -106,14 +119,15 @@ public class Profiler implements Runnable { ...@@ -106,14 +119,15 @@ public class Profiler implements Runnable {
private void run(String... args) { private void run(String... args) {
if (args.length == 0) { if (args.length == 0) {
System.out.println("Show profiling data"); 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:"); System.out.println("Processes:");
String processes = exec("jps", "-l"); String processes = exec("jps", "-l");
System.out.println(processes); System.out.println(processes);
return; return;
} }
pid = Integer.parseInt(args[0]);
start = System.currentTimeMillis(); start = System.currentTimeMillis();
if (args[0].matches("\\d+")) {
pid = Integer.parseInt(args[0]);
long last = 0; long last = 0;
while (true) { while (true) {
tick(); tick();
...@@ -125,6 +139,31 @@ public class Profiler implements Runnable { ...@@ -125,6 +139,31 @@ public class Profiler implements Runnable {
} }
} }
} }
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() { private static List<Object[]> getRunnableStackTraces() {
ArrayList<Object[]> list = new ArrayList<Object[]>(); ArrayList<Object[]> list = new ArrayList<Object[]>();
...@@ -144,10 +183,17 @@ public class Profiler implements Runnable { ...@@ -144,10 +183,17 @@ public class Profiler implements Runnable {
} }
private static List<Object[]> readRunnableStackTraces(int pid) { private static List<Object[]> readRunnableStackTraces(int pid) {
ArrayList<Object[]> list = new ArrayList<Object[]>();
try { try {
String jstack = exec("jstack", "" + pid); String jstack = exec("jstack", "" + pid);
LineNumberReader r = new LineNumberReader(new StringReader(jstack)); 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) { while (true) {
String line = r.readLine(); String line = r.readLine();
if (line == null) { if (line == null) {
...@@ -187,9 +233,6 @@ public class Profiler implements Runnable { ...@@ -187,9 +233,6 @@ public class Profiler implements Runnable {
} }
} }
return list; return list;
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
private static String exec(String... args) { private static String exec(String... args) {
...@@ -292,6 +335,11 @@ public class Profiler implements Runnable { ...@@ -292,6 +335,11 @@ public class Profiler implements Runnable {
} else { } else {
list = getRunnableStackTraces(); list = getRunnableStackTraces();
} }
threadDumps++;
processList(list);
}
private void processList(List<Object[]> list) {
for (Object[] dump : list) { for (Object[] dump : list) {
if (startsWithAny(dump[0].toString(), ignoreThreads)) { if (startsWithAny(dump[0].toString(), ignoreThreads)) {
continue; continue;
...@@ -377,8 +425,14 @@ public class Profiler implements Runnable { ...@@ -377,8 +425,14 @@ public class Profiler implements Runnable {
private String getTopTraces(int count) { private String getTopTraces(int count) {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
buff.append("Profiler: top ").append(count).append(" stack trace(s) of ").append(time). buff.append("Profiler: top ").append(count).append(" stack trace(s) of ");
append(" ms:").append(LINE_SEPARATOR); 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) { if (counts.size() == 0) {
buff.append("(none)").append(LINE_SEPARATOR); buff.append("(none)").append(LINE_SEPARATOR);
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论