diff --git a/src/main/java/de/steamwar/Agent.java b/src/main/java/de/steamwar/Agent.java index 05f9344..6031d87 100644 --- a/src/main/java/de/steamwar/Agent.java +++ b/src/main/java/de/steamwar/Agent.java @@ -9,7 +9,7 @@ public class Agent { public static void premain(String args, Instrumentation inst) { if ("start".equals(args)) { - sampler = new Sampler(true); + sampler = new Sampler(); } } @@ -17,7 +17,7 @@ public class Agent { switch (args) { case "start": if(sampler == null) - sampler = new Sampler(false); + sampler = new Sampler(); break; case "stop": if(sampler != null) diff --git a/src/main/java/de/steamwar/Main.java b/src/main/java/de/steamwar/Main.java index 48f2483..41502b1 100644 --- a/src/main/java/de/steamwar/Main.java +++ b/src/main/java/de/steamwar/Main.java @@ -3,9 +3,10 @@ package de.steamwar; import com.sun.tools.attach.*; import com.sun.tools.attach.spi.AttachProvider; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; public class Main { @@ -22,29 +23,18 @@ public class Main { } public static void main(String[] args) { - if(args.length == 0) { - for(AttachProvider provider : AttachProvider.providers()) { - for(VirtualMachineDescriptor vmd : provider.listVirtualMachines()) { - System.out.println(vmd.id() + " " + vmd.displayName()); - } - } - return; - } - try { - VirtualMachine vm = VirtualMachine.attach(args[0]); + VirtualMachine vm = VirtualMachine.attach(args.length > 0 ? args[0] : getVmId()); - if(args.length == 1 || !"heap".equals(args[1])) { + if(args.length > 1 && "heap".equals(args[1])) { + vm.loadAgent(jarPath.getAbsolutePath(), "heap"); + } else { vm.loadAgent(jarPath.getAbsolutePath(), "start"); System.out.println("Press keyboard to stop sampling..."); System.in.read(); vm.loadAgent(jarPath.getAbsolutePath(), "stop"); - - new ProcessBuilder("xdot", "samples.dot").directory(jarPath.getParentFile()).start(); - } else { - vm.loadAgent(jarPath.getAbsolutePath(), "heap"); } vm.detach(); @@ -53,4 +43,16 @@ public class Main { e.printStackTrace(); } } + + private static String getVmId() throws IOException { + List vms = new ArrayList<>(); + for(AttachProvider provider : AttachProvider.providers()) { + for(VirtualMachineDescriptor vmd : provider.listVirtualMachines()) { + System.out.println("[" + vms.size() + "] " + vmd.id() + " " + vmd.displayName()); + vms.add(vmd.id()); + } + } + + return new BufferedReader(new InputStreamReader(System.in)).readLine(); + } } diff --git a/src/main/java/de/steamwar/OpenJ9.java b/src/main/java/de/steamwar/OpenJ9.java index ada2f2d..1001f6e 100644 --- a/src/main/java/de/steamwar/OpenJ9.java +++ b/src/main/java/de/steamwar/OpenJ9.java @@ -12,7 +12,7 @@ public class OpenJ9 { public static void heapdump() { try { - Dump.heapDumpToFile(new File(Main.jarPath.getParentFile(), "heap.phd").getPath()); + Dump.heapDumpToFile(new File(System.getProperty("user.home"), "heap.phd").getPath()); } catch (InvalidDumpOptionException e) { Logger.getGlobal().log(Level.WARNING, "Could not perform heap dump", e); } diff --git a/src/main/java/de/steamwar/Sampler.java b/src/main/java/de/steamwar/Sampler.java index 874c118..d6fd002 100644 --- a/src/main/java/de/steamwar/Sampler.java +++ b/src/main/java/de/steamwar/Sampler.java @@ -17,47 +17,50 @@ public class Sampler { waitingMethods.add("io.netty.channel.epoll.Native.epollWait"); waitingMethods.add("io.netty.channel.epoll.Native.epollWait0"); waitingMethods.add("org.bukkit.craftbukkit.libs.jline.internal.NonBlockingInputStream.read"); - waitingMethods.add("com.ibm.lang.management.internal.MemoryNotificationThread.processNotificationLoop"); waitingMethods.add("net.minecrell.terminalconsole.SimpleTerminalConsole.readCommands"); - waitingMethods.add("sun.nio.ch.SocketDispatcher.read0"); + waitingMethods.add("com.ibm.lang.management.internal.MemoryNotificationThread.processNotificationLoop"); waitingMethods.add("openj9.internal.tools.attach.target.IPC.waitSemaphore"); waitingMethods.add("sun.nio.ch.Net.poll"); - waitingMethods.add("java.lang.ProcessHandleImpl.waitForProcessExit0"); - waitingMethods.add("java.io.FileInputStream.readBytes"); - waitingMethods.add("java.util.concurrent.locks.LockSupport.parkNanos"); + waitingMethods.add("sun.nio.ch.SocketDispatcher.read0"); waitingMethods.add("sun.awt.X11.XToolkit.waitForEvents"); + waitingMethods.add("java.lang.ProcessHandleImpl.waitForProcessExit0"); waitingMethods.add("java.lang.ref.Reference.waitForReferencePendingList"); + waitingMethods.add("java.util.concurrent.locks.LockSupport.parkNanos"); + waitingMethods.add("java.io.FileInputStream.readBytes"); } - private static final List omittedMethods = new ArrayList<>(); + private static final Set omittedMethods = new HashSet<>(); static { omittedMethods.add("java.lang.reflect.Method.invoke"); omittedMethods.add("java.lang.Thread.run"); - omittedMethods.add("jdk.internal"); - omittedMethods.add("java.util.stream"); omittedMethods.add("java.util.Iterator.forEachRemaining"); omittedMethods.add("java.lang.Iterable.forEach"); + omittedMethods.add("java.util.ArrayList.forEach"); + omittedMethods.add("java.util.Map.forEach"); + + //TODO: Rework to concrete functions + omittedMethods.add("jdk.internal"); + omittedMethods.add("java.util.stream"); omittedMethods.add("java.util.Spliterators"); omittedMethods.add("java.util.ArrayList$ArrayListSpliterator"); omittedMethods.add("java.util.AbstractList$RandomAccessSpliterator"); - omittedMethods.add("java.util.ArrayList.forEach"); - omittedMethods.add("java.util.Map.forEach"); omittedMethods.add("java.util.concurrent"); } private final Map traces = new HashMap<>(); private final Thread samplerThread; - private final boolean showDot; + private final Thread shutdownHook; private boolean shutdown = false; private int sampleRuns; - public Sampler(boolean showDot) { - this.showDot = showDot; + public Sampler() { samplerThread = new Thread(this::run, "Sampler"); samplerThread.setDaemon(true); samplerThread.start(); + shutdownHook = new Thread(this::stop, "SamplerShutdownHook"); + Runtime.getRuntime().addShutdownHook(shutdownHook); } public int getSampleRuns() { @@ -72,14 +75,18 @@ public class Sampler { Thread.currentThread().interrupt(); } - File output = new File(Main.jarPath.getParentFile(), "samples.dot"); + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (IllegalStateException e) { + //ignored + } + + File output = new File(System.getProperty("user.home"), "samples.dot"); try { OutputStreamWriter writer = new FileWriter(output); toDot(writer); writer.flush(); writer.close(); - if(showDot) - new ProcessBuilder("xdot", "samples.dot").directory(Main.jarPath.getParentFile()).start(); } catch (IOException e) { e.printStackTrace(); } @@ -137,7 +144,7 @@ public class Sampler { for(int i = stack.length - 1; i >= 0; i--) { String id = ids[i]; - if(!previousIds.add(id) || omittedMethods.stream().anyMatch(id::startsWith)) + if(!previousIds.add(id) || omittedMethods.contains(id)) continue; Trace trace = traces.computeIfAbsent(id, id1 -> new Trace(this, id1)); diff --git a/src/main/java/de/steamwar/Trace.java b/src/main/java/de/steamwar/Trace.java index f3335c9..db0c2ce 100644 --- a/src/main/java/de/steamwar/Trace.java +++ b/src/main/java/de/steamwar/Trace.java @@ -30,7 +30,7 @@ public class Trace { } private boolean filtered() { - return (samples[1] + samples[2]) / (double) sampler.getSampleRuns() < Sampler.FILTER; + return Arrays.stream(samples).sum() / (double) sampler.getSampleRuns() < Sampler.FILTER; } public void add(Thread.State state, Trace predecessor) { diff --git a/steamwarci.yml b/steamwarci.yml new file mode 100644 index 0000000..582ed6f --- /dev/null +++ b/steamwarci.yml @@ -0,0 +1,5 @@ +build: + - "mvn package -B" + +artifacts: + "/binarys/LixfelsProfiler.jar": "target/LixfelsProfiler.jar"