org.h2.util.Profiler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of h2-mvstore Show documentation
Show all versions of h2-mvstore Show documentation
Fork of h2database to maintain Java 8 compatibility
The newest version!
/*
* Copyright 2004-2023 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.lang.instrument.Instrumentation;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 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, or files containing full thread dumps).
*/
public class Profiler implements Runnable {
private static Instrumentation instrumentation;
private static final String LINE_SEPARATOR =
System.getProperty("line.separator", "\n");
private static final int MAX_ELEMENTS = 1000;
public int interval = 2;
public int depth = 48;
public boolean paused;
public boolean sumClasses;
public boolean sumMethods;
private int pid;
private final String[] ignoreLines = (
"java," +
"sun," +
"com.sun.," +
"com.google.common.," +
"com.mongodb.," +
"org.bson.,"
).split(",");
private final String[] ignorePackages = (
"java," +
"sun," +
"com.sun.," +
"com.google.common.," +
"com.mongodb.," +
"org.bson"
).split(",");
private final String[] ignoreThreads = (
"java.lang.Object.wait," +
"java.lang.Thread.dumpThreads," +
"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," +
"java.net.SocketOutputStream.socketWrite," +
"org.eclipse.jetty.io.nio.SelectorManager$SelectSet.doSelect," +
"sun.awt.windows.WToolkit.eventLoop," +
"sun.misc.Unsafe.park," +
"sun.nio.ch.EPollArrayWrapper.epollWait," +
"sun.nio.ch.KQueueArrayWrapper.kevent0," +
"sun.nio.ch.ServerSocketChannelImpl.accept," +
"dalvik.system.VMStack.getThreadStackTrace," +
"dalvik.system.NativeStart.run"
).split(",");
private volatile boolean stop;
private final HashMap counts =
new HashMap<>();
/**
* The summary (usually one entry per package, unless sumClasses is enabled,
* in which case it's one entry per class).
*/
private final HashMap summary =
new HashMap<>();
private int minCount = 1;
private int total;
private Thread thread;
private long start;
private long time;
private int threadDumps;
/**
* This method is called when the agent is installed.
*
* @param agentArgs the agent arguments
* @param inst the instrumentation object
*/
public static void premain(@SuppressWarnings("unused") String agentArgs, Instrumentation inst) {
instrumentation = inst;
}
/**
* Get the instrumentation object if started as an agent.
*
* @return the instrumentation, or null
*/
public static Instrumentation getInstrumentation() {
return instrumentation;
}
/**
* Run the command line version of the profiler. The JDK (jps and jstack)
* need to be in the path.
*
* @param args the process id of the process - if not set the java processes
* are listed
*/
public static void main(String... args) {
new Profiler().run(args);
}
private void run(String... args) {
if (args.length == 0) {
System.out.println("Show profiling data");
System.out.println("Usage: java " + getClass().getName() +
" | ");
System.out.println("Processes:");
String processes = exec("jps", "-l");
System.out.println(processes);
return;
}
start = System.nanoTime();
if (args[0].matches("\\d+")) {
pid = Integer.parseInt(args[0]);
long last = 0;
while (true) {
tick();
long t = System.nanoTime();
if (t - last > TimeUnit.SECONDS.toNanos(5)) {
time = System.nanoTime() - start;
System.out.println(getTopTraces(3));
last = t;
}
}
}
try {
for (String arg : args) {
if (arg.startsWith("-")) {
if ("-classes".equals(arg)) {
sumClasses = true;
} else if ("-methods".equals(arg)) {
sumMethods = true;
} else if ("-packages".equals(arg)) {
sumClasses = false;
sumMethods = false;
} else {
throw new IllegalArgumentException(arg);
}
continue;
}
Path file = Paths.get(arg);
try (Reader reader = Files.newBufferedReader(file)) {
LineNumberReader r = new LineNumberReader(reader);
for (String line; (line = r.readLine()) != null;) {
if (line.startsWith("Full thread dump")) {
threadDumps++;
}
}
}
try (Reader reader = Files.newBufferedReader(file)) {
processList(readStackTrace(new LineNumberReader(reader)));
}
}
System.out.println(getTopTraces(5));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static List