diff --git a/sootup.core/src/main/java/sootup/core/transform/BodyInterceptorMetric.java b/sootup.core/src/main/java/sootup/core/transform/BodyInterceptorMetric.java new file mode 100644 index 00000000000..2e8e923c863 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/transform/BodyInterceptorMetric.java @@ -0,0 +1,50 @@ +package sootup.core.transform; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2024 Sahil Agichani + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +public class BodyInterceptorMetric { + + private long runtime; + private long memoryUsage; + + public BodyInterceptorMetric(long runtime, long memoryUsage) { + this.runtime = runtime; + this.memoryUsage = memoryUsage; + } + + public long getRuntime() { + return runtime; + } + + public void setRuntime(long runtime) { + this.runtime = runtime; + } + + public long getMemoryUsage() { + return memoryUsage; + } + + public void setMemoryUsage(long memoryUsage) { + this.memoryUsage = memoryUsage; + } +} diff --git a/sootup.core/src/main/java/sootup/core/transform/RunTimeBodyInterceptor.java b/sootup.core/src/main/java/sootup/core/transform/RunTimeBodyInterceptor.java new file mode 100644 index 00000000000..b9d54d77175 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/transform/RunTimeBodyInterceptor.java @@ -0,0 +1,64 @@ +package sootup.core.transform; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2024 Sahil Agichani + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import javax.annotation.Nonnull; +import sootup.core.model.Body; +import sootup.core.views.View; + +public class RunTimeBodyInterceptor implements BodyInterceptor { + + private BodyInterceptorMetric biMetric = new BodyInterceptorMetric(0L, 0L); + + private final BodyInterceptor bodyInterceptor; + + public RunTimeBodyInterceptor(BodyInterceptor bodyInterceptor) { + this.bodyInterceptor = bodyInterceptor; + } + + public BodyInterceptorMetric getBiMetric() { + return biMetric; + } + + public BodyInterceptor getBodyInterceptor() { + return bodyInterceptor; + } + + @Override + public void interceptBody(@Nonnull Body.BodyBuilder builder, @Nonnull View view) { + long startTime = System.currentTimeMillis(); // Start time + final int MB = 1024 * 1024; + Runtime runtime = Runtime.getRuntime(); + long usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory(); + + bodyInterceptor.interceptBody(builder, view); + + long endTime = System.currentTimeMillis(); // End time + long duration = endTime - startTime; + long usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory(); + long memoryUsed = (usedMemoryAfter - usedMemoryBefore) / MB; + + biMetric.setRuntime(biMetric.getRuntime() + duration); + biMetric.setMemoryUsage(biMetric.getMemoryUsage() + memoryUsed); + } +} diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/RuntimeJarConversionTests.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/RuntimeJarConversionTests.java index 63b933f07cc..fcf56f32ac0 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/RuntimeJarConversionTests.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/RuntimeJarConversionTests.java @@ -3,6 +3,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; @@ -14,12 +16,16 @@ import sootup.core.model.SootMethod; import sootup.core.model.SourceType; import sootup.core.transform.BodyInterceptor; +import sootup.core.transform.BodyInterceptorMetric; +import sootup.core.transform.RunTimeBodyInterceptor; import sootup.core.util.DotExporter; import sootup.core.util.Utils; import sootup.java.bytecode.inputlocation.DefaultRTJarAnalysisInputLocation; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; import sootup.java.core.interceptors.BytecodeBodyInterceptors; import sootup.java.core.interceptors.CopyPropagator; import sootup.java.core.interceptors.DeadAssignmentEliminator; +import sootup.java.core.interceptors.TypeAssigner; import sootup.java.core.views.JavaView; @Tag("Java8") @@ -121,4 +127,40 @@ public void testExample() { /* Example to start quickly */ convertMethod(""); } + + /** e.g. to measure Runtime (Time and Memory Usage) of every interceptor */ + @Test + public void runTimeOfBodyInterceptorOnJar() { + // Note: mrjar.jar used just for test purpose, you can put any jar file. + String baseDir = "../shared-test-resources/multi-release-jar/mrjar.jar"; + // List bodyInterceptorsList = + // BytecodeBodyInterceptors.Default.getBodyInterceptors(); + List bodyInterceptorsList = + Arrays.asList(new TypeAssigner(), new CopyPropagator()); + List runTimeBodyInterceptorsList = new ArrayList<>(); + for (BodyInterceptor bodyInterceptor : bodyInterceptorsList) { + RunTimeBodyInterceptor runTimeBodyInterceptor = new RunTimeBodyInterceptor(bodyInterceptor); + runTimeBodyInterceptorsList.add(runTimeBodyInterceptor); + } + AnalysisInputLocation inputLocation = + new JavaClassPathAnalysisInputLocation( + baseDir, SourceType.Library, Collections.unmodifiableList(runTimeBodyInterceptorsList)); + JavaView view = new JavaView(inputLocation); + view.getClasses() + .forEach(javaSootClass -> javaSootClass.getMethods().forEach(SootMethod::getBody)); + runTimeBodyInterceptorsList.forEach( + runTimeBodyInterceptor -> { + BodyInterceptorMetric biMetric = runTimeBodyInterceptor.getBiMetric(); + System.out.println( + runTimeBodyInterceptor.getBodyInterceptor() + + " took " + + biMetric.getRuntime() + + " ms."); + System.out.println( + runTimeBodyInterceptor.getBodyInterceptor() + + " consumed " + + biMetric.getMemoryUsage() + + " MB."); + }); + } }