ex8 now follows guidelines in project description
This commit is contained in:
parent
cc38d2872b
commit
6a7bf23a9d
10 changed files with 69 additions and 134 deletions
|
@ -1,14 +1,11 @@
|
||||||
package ex5;
|
package ex5;
|
||||||
|
|
||||||
import ch.usi.dag.disl.annotation.Before;
|
import ch.usi.dag.disl.annotation.Before;
|
||||||
import ch.usi.dag.disl.dynamiccontext.DynamicContext;
|
|
||||||
import ch.usi.dag.disl.marker.BodyMarker;
|
import ch.usi.dag.disl.marker.BodyMarker;
|
||||||
import ch.usi.dag.disl.marker.BytecodeMarker;
|
import ch.usi.dag.disl.marker.BytecodeMarker;
|
||||||
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
|
||||||
//import jdk.internal.misc.Unsafe;
|
|
||||||
|
|
||||||
public class Instrumentation {
|
public class Instrumentation {
|
||||||
@Before(marker = BytecodeMarker.class, args = "new,newarray,anewarray,multianewarray", scope = "*")
|
@Before(marker = BytecodeMarker.class, args = "new,newarray,anewarray,multianewarray")
|
||||||
static void handleSafeAllocation() {
|
static void handleSafeAllocation() {
|
||||||
Profiler.addSafeAllocation();
|
Profiler.addSafeAllocation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,17 @@
|
||||||
package ex6;
|
package ex6;
|
||||||
|
|
||||||
import ch.usi.dag.disl.annotation.Before;
|
import ch.usi.dag.disl.annotation.Before;
|
||||||
|
import ch.usi.dag.disl.marker.BasicBlockMarker;
|
||||||
import ch.usi.dag.disl.marker.BytecodeMarker;
|
import ch.usi.dag.disl.marker.BytecodeMarker;
|
||||||
|
import ch.usi.dag.disl.staticcontext.LoopStaticContext;
|
||||||
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.util.Printer;
|
|
||||||
|
|
||||||
public class Instrumentation {
|
public class Instrumentation {
|
||||||
|
|
||||||
final static String[] BRANCH_OP_NAMES = new String[]{
|
@Before(marker = BasicBlockMarker.class,
|
||||||
Printer.OPCODES[Opcodes.GOTO],
|
scope = "ex6.MainThread.*",
|
||||||
Printer.OPCODES[Opcodes.IF_ACMPEQ],
|
guard = IsFirstInLoopGuard.class)
|
||||||
Printer.OPCODES[Opcodes.IF_ACMPNE],
|
static void handleLoopInstruction(final LoopStaticContext lsc, final MethodStaticContext msc) {
|
||||||
Printer.OPCODES[Opcodes.IF_ICMPEQ],
|
Profiler.countLoop(msc.thisMethodFullName());
|
||||||
Printer.OPCODES[Opcodes.IF_ICMPGE],
|
|
||||||
Printer.OPCODES[Opcodes.IF_ICMPLE],
|
|
||||||
Printer.OPCODES[Opcodes.IF_ICMPGT],
|
|
||||||
Printer.OPCODES[Opcodes.IF_ICMPLT],
|
|
||||||
Printer.OPCODES[Opcodes.IF_ICMPNE]
|
|
||||||
};
|
|
||||||
// static final String BRANCH_OP_NAMES_STRING = String.join(",", BRANCH_OP_NAMES);
|
|
||||||
static final String BRANCH_OP_NAMES_STRING = "GOTO,IF_ACMPEQ,IF_ACMPNE,IF_ICMPEQ,IF_ICMPGE,IF_ICMPLE,IF_ICMPGT,IF_ICMPLT,IF_ICMPNE";
|
|
||||||
|
|
||||||
|
|
||||||
@Before(marker = BytecodeMarker.class, args = BRANCH_OP_NAMES_STRING, scope = "ex6.MainThread.*", guard = IsLoopInstructionGuard.class)
|
|
||||||
static void handleLoopInstruction(MethodStaticContext mc) {
|
|
||||||
final String methodName = mc.thisMethodFullName();
|
|
||||||
Profiler.countLoop(methodName);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
DiSLProject2022/src-profiler/ex6/IsFirstInLoopGuard.java
Normal file
11
DiSLProject2022/src-profiler/ex6/IsFirstInLoopGuard.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package ex6;
|
||||||
|
|
||||||
|
import ch.usi.dag.disl.annotation.GuardMethod;
|
||||||
|
import ch.usi.dag.disl.staticcontext.LoopStaticContext;
|
||||||
|
|
||||||
|
public class IsFirstInLoopGuard {
|
||||||
|
@GuardMethod
|
||||||
|
public static boolean isLoopInstruction(final LoopStaticContext lsc) {
|
||||||
|
return lsc.isFirstOfLoop();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
package ex6;
|
|
||||||
|
|
||||||
import ch.usi.dag.disl.annotation.GuardMethod;
|
|
||||||
|
|
||||||
public class IsLoopInstructionGuard {
|
|
||||||
@GuardMethod
|
|
||||||
public static boolean isLoopInstruction(LoopContext lc) {
|
|
||||||
return lc.isLoopInstruction();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package ex6;
|
|
||||||
|
|
||||||
import ch.usi.dag.disl.staticcontext.AbstractStaticContext;
|
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
|
||||||
import org.objectweb.asm.tree.InsnList;
|
|
||||||
import org.objectweb.asm.tree.JumpInsnNode;
|
|
||||||
|
|
||||||
public class LoopContext extends AbstractStaticContext {
|
|
||||||
// considered loop instruction if loop footer.
|
|
||||||
public boolean isLoopInstruction() {
|
|
||||||
final InsnList insList = staticContextData.getMethodNode().instructions;
|
|
||||||
final AbstractInsnNode ins = staticContextData.getRegionStart();
|
|
||||||
if (ins instanceof final JumpInsnNode jIns) {
|
|
||||||
final int nextInsOffset = insList.indexOf(jIns.label);
|
|
||||||
final int insOffset = insList.indexOf(jIns);
|
|
||||||
return nextInsOffset < insOffset;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ public final class Profiler {
|
||||||
static {
|
static {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
for (final var entry : methodToLoopCount.entrySet()) {
|
for (final var entry : methodToLoopCount.entrySet()) {
|
||||||
System.out.printf("Method name: %s - # executed loops: %d%n", entry.getKey(), entry.getValue().intValue());
|
System.out.printf("Method name: %s - # executed loops: %d%n", entry.getKey(), entry.getValue().longValue());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,8 @@ public final class Profiler {
|
||||||
private Profiler() {
|
private Profiler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void countLoop(String methodName) {
|
public static void countLoop(String methodName) {
|
||||||
methodToLoopCount.computeIfAbsent(methodName, k -> new LongAdder());
|
methodToLoopCount.computeIfAbsent(methodName, k -> new LongAdder());
|
||||||
methodToLoopCount.get(methodName).increment();
|
methodToLoopCount.get(methodName).increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,48 @@
|
||||||
package ex8;
|
package ex8;
|
||||||
|
|
||||||
|
import ch.usi.dag.disl.annotation.After;
|
||||||
import ch.usi.dag.disl.annotation.Before;
|
import ch.usi.dag.disl.annotation.Before;
|
||||||
|
import ch.usi.dag.disl.annotation.ThreadLocal;
|
||||||
|
import ch.usi.dag.disl.dynamiccontext.DynamicContext;
|
||||||
|
import ch.usi.dag.disl.marker.BodyMarker;
|
||||||
import ch.usi.dag.disl.marker.BytecodeMarker;
|
import ch.usi.dag.disl.marker.BytecodeMarker;
|
||||||
|
import ch.usi.dag.disl.staticcontext.InstructionStaticContext;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
public class Instrumentation {
|
public class Instrumentation {
|
||||||
|
|
||||||
@Before(marker = BytecodeMarker.class, args = "invokestatic,invokespecial,invokevirtual,invokedynamic", scope = "*")
|
@ThreadLocal
|
||||||
static void handleInvoke(InvocationContext ic) {
|
private static long staticCount;
|
||||||
switch (ic.getInvocationOp()){
|
|
||||||
case Opcodes.INVOKEDYNAMIC -> Profiler.countInvoke(Thread.currentThread().getName(), "dynamic");
|
@ThreadLocal
|
||||||
case Opcodes.INVOKEVIRTUAL -> Profiler.countInvoke(Thread.currentThread().getName(), "virtual");
|
private static long dynamicCount;
|
||||||
case Opcodes.INVOKESTATIC -> Profiler.countInvoke(Thread.currentThread().getName(), "static");
|
|
||||||
case Opcodes.INVOKESPECIAL -> Profiler.countInvoke(Thread.currentThread().getName(), "special");
|
@ThreadLocal
|
||||||
|
private static long specialCount;
|
||||||
|
|
||||||
|
@ThreadLocal
|
||||||
|
private static long virtualCount;
|
||||||
|
|
||||||
|
@Before(marker = BytecodeMarker.class,
|
||||||
|
args = "invokestatic, invokespecial, invokevirtual, invokedynamic")
|
||||||
|
static void handleInvoke(final InstructionStaticContext isc) {
|
||||||
|
switch (isc.getOpcode()) {
|
||||||
|
case Opcodes.INVOKESTATIC -> staticCount++;
|
||||||
|
case Opcodes.INVOKEDYNAMIC -> dynamicCount++;
|
||||||
|
case Opcodes.INVOKESPECIAL -> specialCount++;
|
||||||
|
case Opcodes.INVOKEVIRTUAL -> virtualCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After(marker = BodyMarker.class, scope = "void run()", guard = IsNonStaticGuard.class)
|
||||||
|
static void endThread(final DynamicContext dc) {
|
||||||
|
if (dc.getThis() instanceof Thread) {
|
||||||
|
System.out.printf("Thread: %20s - static: %6d - special: %6d - virtual: %6d - dynamic: %6d\n",
|
||||||
|
((Thread) dc.getThis()).getName(),
|
||||||
|
staticCount,
|
||||||
|
specialCount,
|
||||||
|
virtualCount,
|
||||||
|
dynamicCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package ex8;
|
|
||||||
|
|
||||||
import ch.usi.dag.disl.staticcontext.AbstractStaticContext;
|
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
|
||||||
|
|
||||||
public class InvocationContext extends AbstractStaticContext {
|
|
||||||
public int getInvocationOp() {
|
|
||||||
final AbstractInsnNode ins = staticContextData.getRegionStart();
|
|
||||||
return ins.getOpcode();
|
|
||||||
}
|
|
||||||
}
|
|
12
DiSLProject2022/src-profiler/ex8/IsNonStaticGuard.java
Normal file
12
DiSLProject2022/src-profiler/ex8/IsNonStaticGuard.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package ex8;
|
||||||
|
|
||||||
|
import ch.usi.dag.disl.annotation.GuardMethod;
|
||||||
|
import ch.usi.dag.disl.staticcontext.MethodStaticContext;
|
||||||
|
|
||||||
|
public class IsNonStaticGuard {
|
||||||
|
|
||||||
|
@GuardMethod
|
||||||
|
public static boolean isNonStatic(final MethodStaticContext msc) {
|
||||||
|
return !msc.isMethodStatic();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
package ex8;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.LongAdder;
|
|
||||||
|
|
||||||
public final class Profiler {
|
|
||||||
|
|
||||||
|
|
||||||
private record Invocation(String threadName, String invokeType) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
Invocation that = (Invocation) o;
|
|
||||||
return Objects.equals(threadName, that.threadName) && Objects.equals(invokeType, that.invokeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(threadName, invokeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Profiler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<Invocation, LongAdder> invocationToCount = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
// TODO change format to match assignment
|
|
||||||
static {
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
||||||
for (final var entry : invocationToCount.entrySet()) {
|
|
||||||
System.out.printf("Thread: %s Type: %s Count: %d%n",
|
|
||||||
entry.getKey().threadName,
|
|
||||||
entry.getKey().invokeType,
|
|
||||||
entry.getValue().intValue()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void countInvoke(final String threadName, final String invokeType) {
|
|
||||||
final Invocation invocation = new Invocation(threadName, invokeType);
|
|
||||||
invocationToCount.computeIfAbsent(invocation, k -> new LongAdder());
|
|
||||||
invocationToCount.get(invocation).increment();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
Reference in a new issue