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
|
### Compile the agent as JAR
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||||
|
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||||
cd agent/src
|
cd agent/src
|
||||||
find . -name '*.java' -print -exec javac -cp ../lib/\*:. -d ../../out/production/agent \{\} \;
|
find . -name '*.java' -print -exec javac -cp ../lib/\*:. -d ../../out/production/agent \{\} \;
|
||||||
cd ..
|
cd ..
|
||||||
jar cfm agent.jar manifest.txt -C ../out/production/agent .
|
jar cfm agent.jar manifest.txt -C ../out/production/agent .
|
||||||
|
jar tf agent.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
## Profiler
|
## Profiler
|
||||||
|
@ -21,6 +24,8 @@ jar cfm agent.jar manifest.txt -C ../out/production/agent .
|
||||||
### Compile the profiler
|
### Compile the profiler
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||||
|
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||||
cd profiler/src
|
cd profiler/src
|
||||||
find . -name '*.java' -print -exec javac -d ../../out/production/profiler \{\} \;
|
find . -name '*.java' -print -exec javac -d ../../out/production/profiler \{\} \;
|
||||||
cd ../..
|
cd ../..
|
||||||
|
@ -31,6 +36,8 @@ cd ../..
|
||||||
### Compile the application
|
### Compile the application
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_345`
|
||||||
|
export PATH="${JAVA_HOME}/bin:$PATH"
|
||||||
cd application/src
|
cd application/src
|
||||||
find . -name '*.java' -print -exec javac -d ../../out/production/application \{\} \;
|
find . -name '*.java' -print -exec javac -d ../../out/production/application \{\} \;
|
||||||
cd ../..
|
cd ../..
|
||||||
|
@ -39,5 +46,7 @@ cd ../..
|
||||||
### Run application with agent
|
### Run application with agent
|
||||||
|
|
||||||
```shell
|
```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
|
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.ClassFileTransformer;
|
||||||
import java.lang.instrument.IllegalClassFormatException;
|
import java.lang.instrument.IllegalClassFormatException;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class ClassTransformer implements ClassFileTransformer {
|
public class ClassTransformer implements ClassFileTransformer {
|
||||||
public static byte[] instrument(final byte[] bytecode) {
|
public static byte[] instrument(final byte[] bytecode) {
|
||||||
|
@ -24,36 +25,65 @@ public class ClassTransformer implements ClassFileTransformer {
|
||||||
|
|
||||||
private static void instrumentClassNode(final ClassNode cn) {
|
private static void instrumentClassNode(final ClassNode cn) {
|
||||||
for (final MethodNode mn : cn.methods) {
|
for (final MethodNode mn : cn.methods) {
|
||||||
InsnList patch = new InsnList(); // instructions to be added
|
instrumentEntry(cn, mn);
|
||||||
patch.add(new LdcInsnNode("Method " + mn.name + mn.desc + " called"));
|
instrumentExit(cn, mn);
|
||||||
patch.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
|
|
||||||
"ch/usi/inf/sp/dbi/profiler/Profiler",
|
|
||||||
"log",
|
|
||||||
"(Ljava/lang/String;)V"));
|
|
||||||
|
|
||||||
mn.instructions.insert(patch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public byte[] transform(ClassLoader loader,
|
public byte[] transform(ClassLoader loader,
|
||||||
String className,
|
String className,
|
||||||
Class<?> classBeingRedefined,
|
Class<?> classBeingRedefined,
|
||||||
ProtectionDomain protectionDomain,
|
ProtectionDomain protectionDomain,
|
||||||
byte[] classfileBuffer) throws IllegalClassFormatException {
|
byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||||
if (className.startsWith("java/") ||
|
// className.startsWith("java/") ||
|
||||||
className.startsWith("sun/") ||
|
// className.startsWith("javax/") ||
|
||||||
className.startsWith("jdk/") ||
|
// className.startsWith("sun/") ||
|
||||||
className.startsWith("ch/usi/inf/sp/dbi/agent/") ||
|
// className.startsWith("com/sun/") ||
|
||||||
className.startsWith("ch/usi/inf/sp/dbi/profiler/")) {
|
// 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 + ">");
|
System.out.println("Skipping class <" + loader + ", " + className + ">");
|
||||||
return classfileBuffer;
|
return classfileBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("About to transform class <" + loader + ", " + className + ">");
|
System.out.println("About to transform class <" + loader + ", " + className + ">");
|
||||||
try {
|
try {
|
||||||
return instrument(classfileBuffer); // no changes
|
return instrument(classfileBuffer);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace(System.err);
|
e.printStackTrace(System.err);
|
||||||
return classfileBuffer;
|
return classfileBuffer;
|
||||||
|
|
|
@ -2,10 +2,17 @@ package ch.usi.inf.sp.dbi;
|
||||||
|
|
||||||
public class Application {
|
public class Application {
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
sayHi();
|
fib(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sayHi() {
|
public static int fib(int n) {
|
||||||
System.out.println("Hello!");
|
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;
|
package ch.usi.inf.sp.dbi.profiler;
|
||||||
|
|
||||||
|
import javax.sound.midi.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
public class Profiler {
|
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