dangling changes
This commit is contained in:
parent
604bb84031
commit
e589a83c98
4 changed files with 153 additions and 19 deletions
|
@ -10,10 +10,13 @@ export PATH="${JAVA_HOME}/bin:$PATH"
|
|||
### Compile the agent as JAR
|
||||
|
||||
```shell
|
||||
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||
cd agent/src
|
||||
find . -name '*.java' -print -exec javac -cp ../lib/\*:. -d ../../out/production/agent \{\} \;
|
||||
cd ..
|
||||
jar cfm agent.jar manifest.txt -C ../out/production/agent .
|
||||
jar tf agent.jar
|
||||
```
|
||||
|
||||
## Profiler
|
||||
|
@ -21,6 +24,8 @@ jar cfm agent.jar manifest.txt -C ../out/production/agent .
|
|||
### Compile the profiler
|
||||
|
||||
```shell
|
||||
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||
cd profiler/src
|
||||
find . -name '*.java' -print -exec javac -d ../../out/production/profiler \{\} \;
|
||||
cd ../..
|
||||
|
@ -31,6 +36,8 @@ cd ../..
|
|||
### Compile the application
|
||||
|
||||
```shell
|
||||
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||
cd application/src
|
||||
find . -name '*.java' -print -exec javac -d ../../out/production/application \{\} \;
|
||||
cd ../..
|
||||
|
@ -39,5 +46,7 @@ cd ../..
|
|||
### Run application with agent
|
||||
|
||||
```shell
|
||||
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||
java -javaagent:agent/agent.jar=hello -cp out/production/application -Xbootclasspath/p:out/production/profiler ch.usi.inf.sp.dbi.Application
|
||||
```
|
|
@ -8,6 +8,7 @@ import org.objectweb.asm.tree.*;
|
|||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Set;
|
||||
|
||||
public class ClassTransformer implements ClassFileTransformer {
|
||||
public static byte[] instrument(final byte[] bytecode) {
|
||||
|
@ -24,36 +25,65 @@ public class ClassTransformer implements ClassFileTransformer {
|
|||
|
||||
private static void instrumentClassNode(final ClassNode cn) {
|
||||
for (final MethodNode mn : cn.methods) {
|
||||
InsnList patch = new InsnList(); // instructions to be added
|
||||
patch.add(new LdcInsnNode("Method " + mn.name + mn.desc + " called"));
|
||||
patch.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
|
||||
"ch/usi/inf/sp/dbi/profiler/Profiler",
|
||||
"log",
|
||||
"(Ljava/lang/String;)V"));
|
||||
|
||||
mn.instructions.insert(patch);
|
||||
instrumentEntry(cn, mn);
|
||||
instrumentExit(cn, mn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void instrumentEntry(ClassNode cn, MethodNode mn) {
|
||||
InsnList patch = new InsnList(); // instructions to be added
|
||||
patch.add(new LdcInsnNode(cn.name));
|
||||
patch.add(new LdcInsnNode(mn.name));
|
||||
patch.add(new LdcInsnNode(mn.desc));
|
||||
patch.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
|
||||
"ch/usi/inf/sp/dbi/profiler/Profiler",
|
||||
"entry",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"));
|
||||
|
||||
mn.instructions.insert(patch);
|
||||
}
|
||||
|
||||
private static void instrumentExit(ClassNode cn, MethodNode mn) {
|
||||
for (AbstractInsnNode i : mn.instructions) {
|
||||
|
||||
if (i.getOpcode() >= Opcodes.IRETURN && i.getOpcode() <= Opcodes.RETURN) {
|
||||
InsnList patch = new InsnList(); // instructions to be added
|
||||
patch.add(new LdcInsnNode(cn.name));
|
||||
patch.add(new LdcInsnNode(mn.name));
|
||||
patch.add(new LdcInsnNode(mn.desc));
|
||||
patch.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
|
||||
"ch/usi/inf/sp/dbi/profiler/Profiler",
|
||||
"exit",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"));
|
||||
|
||||
mn.instructions.insertBefore(i, patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader loader,
|
||||
String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||
if (className.startsWith("java/") ||
|
||||
className.startsWith("sun/") ||
|
||||
className.startsWith("jdk/") ||
|
||||
className.startsWith("ch/usi/inf/sp/dbi/agent/") ||
|
||||
className.startsWith("ch/usi/inf/sp/dbi/profiler/")) {
|
||||
// className.startsWith("java/") ||
|
||||
// className.startsWith("javax/") ||
|
||||
// className.startsWith("sun/") ||
|
||||
// className.startsWith("com/sun/") ||
|
||||
// className.startsWith("jdk/") ||
|
||||
|
||||
if (!className.startsWith("ch/usi/inf/sp/dbi/") ||
|
||||
className.startsWith("ch/usi/inf/sp/dbi/agent/") ||
|
||||
className.startsWith("ch/usi/inf/sp/dbi/profiler/")) {
|
||||
System.out.println("Skipping class <" + loader + ", " + className + ">");
|
||||
return classfileBuffer;
|
||||
}
|
||||
|
||||
System.out.println("About to transform class <" + loader + ", " + className + ">");
|
||||
try {
|
||||
return instrument(classfileBuffer); // no changes
|
||||
return instrument(classfileBuffer);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace(System.err);
|
||||
return classfileBuffer;
|
||||
|
|
|
@ -2,10 +2,17 @@ package ch.usi.inf.sp.dbi;
|
|||
|
||||
public class Application {
|
||||
public static void main(String... args) {
|
||||
sayHi();
|
||||
fib(20);
|
||||
}
|
||||
|
||||
public static void sayHi() {
|
||||
System.out.println("Hello!");
|
||||
public static int fib(int n) {
|
||||
System.out.println("fib(" + n + ")");
|
||||
if (n == 0 || n == 1) {
|
||||
return n;
|
||||
} else {
|
||||
int i = fib(n-1) + fib(n-2);
|
||||
System.out.println("fib(" + n + ") = " + i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,95 @@
|
|||
package ch.usi.inf.sp.dbi.profiler;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
import javax.swing.*;
|
||||
|
||||
public class Profiler {
|
||||
public static void log(String what) {
|
||||
System.out.println("PROFILER LOG: " + what);
|
||||
|
||||
private static final DefaultListModel<String> model = new DefaultListModel<>();
|
||||
private static int size = 0;
|
||||
|
||||
static {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
JFrame frame = new JFrame("Profiler");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
model.add(0, "hello");
|
||||
JList<String> list = new JList<>(model);
|
||||
JScrollPane p = new JScrollPane(list);
|
||||
frame.add(p);
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static MidiEvent createProgramChangeEvent(int channel, int program) throws InvalidMidiDataException {
|
||||
ShortMessage message = new ShortMessage();
|
||||
message.setMessage(ShortMessage.PROGRAM_CHANGE, channel, program, 0);
|
||||
return new MidiEvent(message, 0);
|
||||
}
|
||||
|
||||
public static void play() throws InterruptedException {
|
||||
final Thread midi = new Thread(() -> {
|
||||
try {
|
||||
Sequencer player = MidiSystem.getSequencer();
|
||||
player.open();
|
||||
|
||||
Sequence seq = new Sequence(Sequence.PPQ, 4);
|
||||
|
||||
Track track = seq.createTrack();
|
||||
|
||||
int channel = 1;
|
||||
|
||||
int pitch = size * 2;
|
||||
pitch = 20 + pitch % 118;
|
||||
|
||||
track.add(createProgramChangeEvent(channel, 54));
|
||||
|
||||
ShortMessage a = new ShortMessage();
|
||||
a.setMessage(ShortMessage.NOTE_ON, channel, pitch, 100);
|
||||
MidiEvent noteOn = new MidiEvent(a, 0);
|
||||
track.add(noteOn);
|
||||
|
||||
ShortMessage b = new ShortMessage();
|
||||
b.setMessage(ShortMessage.NOTE_OFF, channel, pitch, 100);
|
||||
MidiEvent noteOff = new MidiEvent(b, 2);
|
||||
track.add(noteOff);
|
||||
|
||||
player.setSequence(seq);
|
||||
player.start();
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
midi.start();
|
||||
midi.join();
|
||||
}
|
||||
|
||||
public static void entry(String clazz, String method, String desc) {
|
||||
size++;
|
||||
model.add(0, clazz + "." + method + desc);
|
||||
log(clazz, method, desc, "entry");
|
||||
}
|
||||
|
||||
public static void exit(String clazz, String method, String desc) {
|
||||
size--;
|
||||
model.remove(0);
|
||||
log(clazz, method, desc, "exit");
|
||||
}
|
||||
|
||||
private static void log(String clazz, String method, String desc, String type) {
|
||||
try {
|
||||
System.err.println("Profiler: " + type + " " + clazz + "." + method + desc);
|
||||
play();
|
||||
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue