Adding profiling instructions to applications with Soot

Adding profiling instructions to applications with Soot

Feng Qian (fqian@sable.mcgill.ca)

Patrick Lam (plam@sable.mcgill.ca)

March 8, 2000

This tutorial is based on the countgotos example, written byRaja-Vallée-Rai and distributed with Ashes. It is located inashes.examples.countgotos package. The code can be downloaded at

http://www.sable.mcgill.ca/soot/tutorial/profiler/Main.java

At this stage, the developer should have a basic knowledge of Soot,including the SootClass, SootMethod and Unit classes. They aredescribed inthe document about creating a classusing Soot.

Goals

This tutorial describes how to write a BodyTransformer which annotatesJimpleBody's with a goto-counter. In particular, the developer will beable to write code to:

  • Retrieve a desired method from the Scene by signature.
  • Add a field to a class file.
  • Differentiate between various types of Jimple statements.
  • Insert Jimple instructions at a certain point.

The GotoInstrumenter example instruments a class or application to printout the number ofgoto bytecodes executed at run time.

Creating a GotoInstrumenter

We will instrument a class to print out the number of gotoinstructions executed at run time. The general strategy is:

  1. Add a static field gotoCount to the main class.
  2. Insert instructions incrementing gotoCount before eachgoto instruction in each method.
  3. Insert gotoCount print-out instructions before each return statement in 'main' method.
  4. Insert gotoCount print-out statements before eachSystem.exit() invocation in each method.

Once we create a BodyTransformer class and add it to the appropriatePack, it will be invoked for eachBody in the program.

Subclassing BodyTransformer

This example works by creating a Transformer which is added tothe appropriate pack. We thus declare a subclass ofBodyTransformer to carry out our instrumentation:

public class GotoInstrumenter extends BodyTransformer
{
    private static GotoInstrumenter instance = new GotoInstrumenter();
    private GotoInstrumenter() {}

    public static GotoInstrumenter v() { return instance; }

The above code creates a private static instance and an accessor to thatinstance.

    protected void internalTransform(Body body, String phaseName, Map options)
    {

Every BodyTransformer must declare some internalTransformmethod, carrying out the transformation.

Adding a Field

We already know how to add locals to a method body; this is seen inthe createclassexample.We now show how to add a field to a class.

Here, we want to add a counter field to the main class.

Sanity check - find main() method

First of all, we check the 'main' method declaration by its subsignature.

    if (!Scene.v().getMainClass().
              declaresMethod("void main(java.lang.String[])"))
        throw new RuntimeException("couldn't find main() in mainClass");

A couple of notes about this snippet of code. First, note that wecall Scene.v().getMainClass(). This returns theScene'sidea of the main class; in application mode, it is the file specifiedon the command-line, and in single-file mode, it is the last filespecified on the command-line. Also, note that if we fail, thenaRuntimeException is thrown. It is not worthwhile to use a checkedexception in this case.

The main class for a Java program will always have subsignature(the Soot word for a complete method signature).voidmain(java.lang.String[]). The call to declaresMethod returns true if a method with this subsignature is declared in thisclass.

Fetching or adding the field

Now, if we've already added the field, we need only fetch it:

    if (addedFieldToMainClassAndLoadedPrintStream)
        gotoCounter = Scene.v().getMainClass().getFieldByName("gotoCount");

Otherwise, we need to add it.

    else
    {
        // Add gotoCounter field
        gotoCounter = new SootField("gotoCount", LongType.v(), 
                                        Modifier.STATIC);
        Scene.v().getMainClass().addField(gotoCounter);

Here, we create a new instance of SootField, for a static fieldcontaining along, named gotoCount. This is the fieldwhich will be incremented each time we do agoto. We add it tothe main class.

        // Just in case, resolve the PrintStream SootClass.
        Scene.v().loadClassAndSupport("java.io.PrintStream");
        javaIoPrintStream = Scene.v().getSootClass("java.io.PrintStream");
    
        addedFieldToMainClassAndLoadedPrintStream = true;
    }
We will use the java.io.PrintStream method, so we load it justin case.

Add locals and statements

Recall that a BodyTransformer operates on an existing methodbody. In this step, locals are added to the body, and profiling structionsare inserted while iterating over the statements of the body.

We first use the method's signature to check if it is a mainmethod or not:

    boolean isMainMethod = body.getMethod().getSubSignature()
                .equals("void main(java.lang.String[])");
We could also check to see if body.getMethod().getDeclaringClass()is the main class, but we don't bother.

Next, a local is added; we already know how to do this.

    Local tmpLocal = Jimple.v().newLocal("tmp", LongType.v());
    body.getLocals().add(tmpLocal);

Here, we are inserting statements at certain programpoints. We look for specific statements by iterating over theUnits chain; in Jimple, this chain is filled withStmts.

    Iterator stmtIt = body.getUnits().snapshotIterator();
    while (stmtIt.hasNext())
    {
        Stmt s = (Stmt) stmtIt.next();
        if (s instanceof GotoStmt)
        {
            /* Insert profiling instructions before s. */
        }
        else if (s instanceof InvokeStmt)
        {
            /* Check if it is a System.exit() statement.
             * If it is, insert print-out statement before s.
             */
        }
        else if (isMainMethod && (s instanceof ReturnStmt 
                     || s instanceof ReturnVoidStmt))
         {
            /* In the main method, before the return statement, insert
             * print-out statements.
             */
         }
    }

The call to getUnits() is akin to that in the createclassexample. It returns a Chain of statements.

The snapshotIterator() returns an iterator over the Chain,but modification of the underlying chain is permitted. A usual iteratorwould throw aConcurrentModificationException in that case!

We can determine the statement type by checking its class with instanceof. Here, we are looking at four different statement types:GotoStmt,InvokeStmt, ReturnStmt and ReturnVoidStmt.

Before every GotoStmt, we insert instructions that increase thecounter. The instructions in Jimple are:

        tmpLong = <classname: long gotoCount>;
        tmpLong = tmpLong + 1L;
        <classname: long gotoCount> = tmpLong;

Creating a reference to a static field is done via a call toJimple.v().newStaticFieldRef(gotoCounter.makeRef()). The entireassignment statement is created with thenewAssignStmt method.

    AssignStmt toAdd1 = Jimple.v().newAssignStmt(tmpLong,
                                Jimple.v().newStaticFieldRef(gotoCounter.makeRef()));

The new statements can then be added to the body by invoking the insertBefore() method. There are also some other methods that canadd statements to a body. We have seen one of them increateclass example, add(). Note that above, we need to get aSootFieldRef from the SootField gotoCounter, in order to construct theJimple StaticFieldRef grammar chunk properly.

    units.insertBefore(toAdd1, s);

We have thus added profiling instructions before every goto statement.

It is quite dandy to keep counters; they are useless unlessoutputted. We add printing statements before calls toSystem.exit(). This is done similarly to what we did for gotostatements, except that we will look more deeply into the Jimplestatements and expressions.

    InvokeExpr iexpr = (InvokeExpr) ((InvokeStmt)s).getInvokeExpr();
    if (iexpr instanceof StaticInvokeExpr)
    {
        SootMethod target = ((StaticInvokeExpr)iexpr).getMethod();
        if (target.getSignature().equals
                    ("<java.lang.System: void exit(int)>"))
        {
            /* insert printing statements here */
        }
    }

Every InvokeStmt has an InvokeExpr. The InvokeExpr must be able to return the target method. Again, we can use signatures to test for the wanted method.

We already saw how to make printing statements in createclassexample. Here is the generated Jimple code.

    tmpRef = <java.lang.System: java.io.PrintStream out>;
    tmpLong = <test: long gotoCount>;
    virtualinvoke tmpRef.<java.io.PrintStream: void println(long)>(tmpLong);

In the main() method, we must also insert the same statements before eachreturn statement.

Outputting annotated code

Since we are providing a BodyTransformer, the modified Bodyis treated as input to the next phase of Soot, and outputted at the end,as per the Soot options.

Adding this transformation to Soot

The preferred method of adding a transformation to Soot is by providing aMain class in one's own package. This class adds transformerstoPacks, as needed. It then calls soot.Main.main withthe arguments it has been passed. This is demonstrated inashes.examples.countgotos.Main.

Conclusions

In this tutorial, we have seen how to instrument class files in Soot.Usually, anything we want to do can be viewed as a transformer ofclass files. Here, we used more advanced methods than in thecreateclassexample.

Where to find files

The GotoInstrumenter, as described in this document (in BodyTransformer form) is available in theashesBase package.There is one Java file, Main.java, which contains theMain andGotoInstrumenter classes.Full class names are ashes.examples.countgotos.Main and.GotoInstrumenter.

Change Log

  • March 9, 2000: Initial version.
  • March 23, 2000: Changes reflecting that the gotocounter isdistributed with ashes now.
  • Feb 7, 2005: Update calls to Jimple constructors to pass SootFieldRef's and SootMethodRef's where appropriate, using makeRef().

About this document ...

Adding profiling instructions to applications with Soot

This document was generated using theLaTeX2HTML translator Version 2008 (1.71)

Copyright © 1993, 1994, 1995, 1996,Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,Ross Moore, Mathematics Department, Macquarie University, Sydney.

The command line arguments were:
latex2html profiler -split 0 -nonavigation -dir ./

The translation was initiated by Eric Bodden on 2012-01-22


Eric Bodden2012-01-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值