JP2 is an excellent and easy-to-use Java Profiler developed by Binder et al.1). It can be used to count the numbers of executed bytecode instructions to estimate the CPU consumption of a Java program. The basics of calling JP2 are as follows:
java -Xmx2g \ -javaagent:$JP2_HOME/lib/javaagent.jar \ -Xbootclasspath/p:$JP2_HOME/lib/Thread_JP2.jar:$JP2_HOME/lib/asm-all-3.3.jar:$JP2_HOME/lib/jp2.jar \ -Dch.usi.dag.jp2.Output="program.output.gz" \ -Dch.usi.dag.jp2.InstrumentedClasses="ProgramInstrumented" \ -Dch.usi.dag.jp2.UninstrumentedClasses="ProgramUninstrumented" \ -cp YourClasspath YourMainClass
While the previous code works well and allows instrumenting programs in most situations, we faced some difficulties when instrumenting SIP communications2). SIP Communicator is a Java VoIP and instant messaging client using Felix. Felix3) is the Apache implementation of the OSGi specifications, which defines a dynamic service deployment framework. The OSGi specifications4) defines a framework on which service implementations or bundles are plugged and managed by the framework, independently of the underlying running JVM (and its classpath). The framework handles bundle discovery, dependencies, requests, and responses. Each bundle communicates only with/through the framework.
We wanted to count the numbers of executed bytecode instructions of SIP communicator using JP2. When instrumenting SIP Communicator, we ran into several problems, which we fixed as follows.
Exclude Felix classes from being instrumented, so Felix can run without having to know about JP2. We added:
!className.startsWith("org/apache/felix")
to method:
byte[] transform(ClassLoader loader, String className, Class<?> redefiningClass, ProtectionDomain domain, byte[] uninstrumentedBytes)
in class:
ch.usi.dag.jp2.agent.SimpleTransformer
Add a bundle which contains all the classes of JP2 into the build.xml of SIP:
<target name="bundle-jp2"> <jar compress="true" destfile="${bundles.dest}/bundle-jp2.jar" filesetmanifest="skip"> <zipfileset src="${lib.noinst}/jp2/asm-all-3.3.jar" prefix="" /> <zipfileset src="${lib.noinst}/jp2/bcel-5.2.jar" prefix="" /> <zipfileset src="${lib.noinst}/jp2/javaagent.jar" prefix="" /> <zipfileset src="${lib.noinst}/jp2/jp2.jar" prefix="" /> <zipfileset src="${lib.noinst}/jp2/jre-tool.jar" prefix="" /> <zipfileset src="${lib.noinst}/jp2/Thread_JP2.jar" prefix="" /> <zipfileset src="${lib.noinst}/jp2/thread-tool.jar" prefix="" /> <manifest> <attribute name="Export-Package" value="ch.usi.dag.jp2.agent,ch.usi.dag.jp2.rewriting,ch.usi.dag.jp2.runtime,ch.usi.dag.jp2.tools.jre,ch.usi.dag.jp2.tools.thread" /> <attribute name="Bundle-Name" value="JP2" /> <attribute name="Bundle-Description" value="Java Instrument Library." /> <attribute name="Bundle-Version" value="1.0" /> <attribute name="System-Bundle" value="yes" /> </manifest> </jar> </target>
Add the JP2 bundle to felix.client.run.properties:
felix.auto.start.11= \ reference:file:lib/bundle/bundle-jp2.jar
javabin=`which java` SCDIR=$WORKING-DIR LIBPATH=$SCDIR/lib BUNDLEPATH=$SCDIR/sc-bundles CLASSPATH=$LIBPATH/jdic_stub.jar:$LIBPATH/jdic-all.jar:$LIBPATH/felix.jar:$LIBPATH/bcprovider.jar:$SCDIR/sc-bundles/sc-launcher.jar:$SCDIR/sc-bundles/util.jar FELIX_CONFIG=$LIBPATH/felix.client.run.properties LOG_CONFIG=$LIBPATH/logging.properties COMMAND="$javabin -Xmx2g \ -javaagent:$LIBPATH/javaagent.jar \ -Xbootclasspath/p:$LIBPATH/Thread_JP2.jar:$LIBPATH/asm-all-3.3.jar:$LIBPATH/jp2.jar \ -Dch.usi.dag.jp2.Output="sip.output.gz" \ -Dch.usi.dag.jp2.InstrumentedClasses="sipInstrumented" \ -Dch.usi.dag.jp2.UninstrumentedClasses="sipUninstrumented" \ -Dch.usi.dag.jp2.InsterestedPackage="net.java.sip" -classpath $CLASSPATH -Dorg.osgi.framework.bootdelegation=ch.usi.* \ -Djna.library.path=$LIBPATH/native -Dfelix.config.properties=file:$FELIX_CONFIG -Djava.util.logging.config.file=$LOG_CONFIG \ net.java.sip.communicator.launcher.SIPCommunicator" # set add LIBPATH to LD_LIBRARY_PATH for any sc natives (e.g. jmf .so's) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIBPATH/native # make LD_PRELOAD use libaoss so that java doesn't hog on the audio device. export LD_PRELOAD=/usr/lib/libaoss.so # create .sip-commnicator/log in home or otherwise java.util.logging will freak mkdir -p $HOME/.sip-communicator/log cd $SCDIR exec $COMMAND $*
Run this script to execute the instrumented SIP communicator.