diff --git a/DiSLProject2022/src-profiler/ex2/Instrumentation.java b/DiSLProject2022/src-profiler/ex2/Instrumentation.java index 9811186..b79e493 100644 --- a/DiSLProject2022/src-profiler/ex2/Instrumentation.java +++ b/DiSLProject2022/src-profiler/ex2/Instrumentation.java @@ -1,4 +1,43 @@ package ex2; +import ch.usi.dag.disl.annotation.After; +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; + public class Instrumentation { + + @ThreadLocal + static long readCount; + + @ThreadLocal + static long writeCount; + + @Before(marker = BytecodeMarker.class, args = "getfield") + static void beforeGetField() { + readCount++; + } + + @Before(marker = BytecodeMarker.class, args = "putfield") + static void beforePutField() { + writeCount++; + } + + @After(marker = BodyMarker.class, + scope = "void run()", + guard = IsTriviallyThreadGuard.class) + static void onThreadExit() { + Profiler.increment(readCount, writeCount); + } + + @After(marker = BodyMarker.class, + scope = "void run()", + guard = IsNotTriviallyThreadGuard.class) + static void onThreadExit(final DynamicContext dc) { + if (Profiler.isThread(dc.getThis().getClass())) { + Profiler.increment(readCount, writeCount); + } + } } diff --git a/DiSLProject2022/src-profiler/ex2/IsNotTriviallyThreadGuard.java b/DiSLProject2022/src-profiler/ex2/IsNotTriviallyThreadGuard.java new file mode 100644 index 0000000..df6bc7a --- /dev/null +++ b/DiSLProject2022/src-profiler/ex2/IsNotTriviallyThreadGuard.java @@ -0,0 +1,12 @@ +package ex2; + +import ch.usi.dag.disl.annotation.GuardMethod; +import ch.usi.dag.disl.staticcontext.ClassStaticContext; + +public class IsNotTriviallyThreadGuard { + + @GuardMethod + public static boolean isNotTriviallyThread(final ClassStaticContext csc) { + return !IsTriviallyThreadGuard.isThread(csc); + } +} diff --git a/DiSLProject2022/src-profiler/ex2/IsTriviallyThreadGuard.java b/DiSLProject2022/src-profiler/ex2/IsTriviallyThreadGuard.java new file mode 100644 index 0000000..15c8d36 --- /dev/null +++ b/DiSLProject2022/src-profiler/ex2/IsTriviallyThreadGuard.java @@ -0,0 +1,12 @@ +package ex2; + +import ch.usi.dag.disl.annotation.GuardMethod; +import ch.usi.dag.disl.staticcontext.ClassStaticContext; + +public class IsTriviallyThreadGuard { + @GuardMethod + public static boolean isThread(ClassStaticContext csc) { + return csc.getInternalName().equals("java/lang/Thread") || + csc.getSuperClassInternalName().equals("java/lang/Thread"); + } +} diff --git a/DiSLProject2022/src-profiler/ex2/Profiler.java b/DiSLProject2022/src-profiler/ex2/Profiler.java new file mode 100644 index 0000000..2ffe95e --- /dev/null +++ b/DiSLProject2022/src-profiler/ex2/Profiler.java @@ -0,0 +1,38 @@ +package ex2; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.LongAdder; + +public final class Profiler { + + // not concurrent on purpose, since the value of the map is computed with a pure function + // on the map key, and thus we don't care if the value is overwritten as a result of a + // race condition + private static final Map, Boolean> isThread = new HashMap<>(); + + private static final LongAdder reads = new LongAdder(); + + private static final LongAdder writes = new LongAdder(); + + static { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + System.out.printf("Instance field read access: %d\nInstance field write access: %d\n", + reads.longValue(), + writes.longValue()); + })); + } + + private Profiler() { + } + + public static boolean isThread(final Class clazz) { + return isThread.computeIfAbsent(clazz, Thread.class::isAssignableFrom); + } + + public static void increment(long readCount, long writeCount) { + reads.add(readCount); + writes.add(writeCount); + } + +}