package rocks.inspectit.agent.java.instrumentation.asm;
import info.novatec.inspectit.org.objectweb.asm.ClassReader;
import info.novatec.inspectit.org.objectweb.asm.ClassWriter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import rocks.inspectit.agent.java.instrumentation.InstrumenterFactory;
import rocks.inspectit.shared.all.instrumentation.config.impl.MethodInstrumentationConfig;
import rocks.inspectit.shared.all.instrumentation.config.impl.SensorInstrumentationPoint;
import rocks.inspectit.shared.all.instrumentation.config.impl.SpecialInstrumentationPoint;
/**
* Performance test for the {@link ClassInstrumenter} class using JMH framework.
*
* @author Ivan Senic
*
*/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 5)
@Measurement(iterations = 5)
@Fork(value = 1)
@State(Scope.Thread)
public class ClassInstrumenterPerfTest {
private static final InstrumenterFactory INSTRUMENTER_FACTORY = new InstrumenterFactory();
@Param({ "java.lang.String", "java.lang.Boolean" })
private String clazz;
@Param({ "0", "1", "10" })
private int maxMethods;
@Param({ "true", "false" })
private boolean enhancedExceptionSensor;
@Param({ "true", "false" })
private boolean specialMethodInstrumentation;
private Collection<MethodInstrumentationConfig> configs;
@Setup(Level.Iteration)
public void init() throws ClassNotFoundException {
Class<?> instrumentedClass = Class.forName(clazz);
Method[] methods = instrumentedClass.getDeclaredMethods();
configs = new ArrayList<MethodInstrumentationConfig>();
for (int i = 0; (i < maxMethods) && (methods.length > 0); i++) {
int index = RandomUtils.nextInt(methods.length);
Method method = methods[index];
methods = (Method[]) ArrayUtils.remove(methods, index);
MethodInstrumentationConfig instrumentationConfig = new MethodInstrumentationConfig();
instrumentationConfig.setTargetClassFqn(clazz);
instrumentationConfig.setTargetMethodName(method.getName());
instrumentationConfig.setReturnType(method.getReturnType().getName());
if (!specialMethodInstrumentation) {
SensorInstrumentationPoint registeredSensorConfig = new SensorInstrumentationPoint();
instrumentationConfig.setSensorInstrumentationPoint(registeredSensorConfig);
} else {
SpecialInstrumentationPoint specialInstrumentationPoint = new SpecialInstrumentationPoint();
instrumentationConfig.setSpecialInstrumentationPoint(specialInstrumentationPoint);
}
configs.add(instrumentationConfig);
}
}
/**
* Instrumenting methods of class.
*/
@Benchmark
public void instrument() throws InterruptedException, IOException {
ClassReader classReader = new ClassReader(clazz);
LoaderAwareClassWriter classWriter = new LoaderAwareClassWriter(classReader, ClassWriter.COMPUTE_FRAMES, null);
ClassInstrumenter classInstrumenter = new ClassInstrumenter(INSTRUMENTER_FACTORY, classWriter, new ArrayList<MethodInstrumentationConfig>(configs), enhancedExceptionSensor);
classReader.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
}
}