From e589a83c980e5e3bed7ba764ca04feb4a4cc892c Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Wed, 3 Jan 2024 10:14:18 +0100 Subject: [PATCH] dangling changes --- README.md | 9 ++ .../inf/sp/dbi/agent/ClassTransformer.java | 58 +++++++++--- .../src/ch/usi/inf/sp/dbi/Application.java | 13 ++- .../ch/usi/inf/sp/dbi/profiler/Profiler.java | 92 ++++++++++++++++++- 4 files changed, 153 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 6f1b442..25c152d 100644 --- a/README.md +++ b/README.md @@ -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 ``` \ No newline at end of file diff --git a/agent/src/ch/usi/inf/sp/dbi/agent/ClassTransformer.java b/agent/src/ch/usi/inf/sp/dbi/agent/ClassTransformer.java index 3d5b925..b9c4ad8 100644 --- a/agent/src/ch/usi/inf/sp/dbi/agent/ClassTransformer.java +++ b/agent/src/ch/usi/inf/sp/dbi/agent/ClassTransformer.java @@ -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; diff --git a/application/src/ch/usi/inf/sp/dbi/Application.java b/application/src/ch/usi/inf/sp/dbi/Application.java index f667851..c8e8eac 100644 --- a/application/src/ch/usi/inf/sp/dbi/Application.java +++ b/application/src/ch/usi/inf/sp/dbi/Application.java @@ -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; + } } } diff --git a/profiler/src/ch/usi/inf/sp/dbi/profiler/Profiler.java b/profiler/src/ch/usi/inf/sp/dbi/profiler/Profiler.java index 823e294..dfeced1 100644 --- a/profiler/src/ch/usi/inf/sp/dbi/profiler/Profiler.java +++ b/profiler/src/ch/usi/inf/sp/dbi/profiler/Profiler.java @@ -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 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 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); + } } }