Branch Count using Intel Pin Tool

on Reading Time: 4 minutes

Having read this blog post you will be able to create your own tool to count the number of branches. You will also be able to learn the  fundamentals that you would need to do any program analysis using the Intel Pin Tool.

The following guide assumes that you have set-up the pin tool using the guide posted here.

Let me first describe the sections of the tool using a simple example, inscount.cpp. We will be modifying this file to create branchcount.cpp which will ultimately count the number of branch instructions. Open the file using the command,

mkdir /opt/pin-dir/source/tool/Bc //create a folder called Bc to store our tool
cp /opt/pin-dir/source/tool/ManualExamples/inscount.cpp /opt/pin-dir/source/tool/Bc/branchcount.cpp // copy to Bc
vi /opt/pin-dir/source/tool/Bc/branchcount.cpp

You will see the following file.

Section 1

The entry point to the tool is from the main function. By looking at the main method, we will be able to identify the program flow.

  1. As you can see PIN_Init method initializes the pin tool with usage and it is specified in pin.H. For example, if the user inputs an incorrect command, this is the method which detects it.
  2. The Usage method describes the correct usage of the tool.  For now just skip the second line with OutFile. We will come back to this when we are outputting the results to a file.
  3. The main part of our tool, is inside the method INS_AddInstrumentFunction(Instruction, 0); . This method contains our injection logic at each instruction step.
  4. PIN_AddFiniFunction(Fini, 0); specifies the method to be executed when the application ends.
  5. Finally the program execution begins and monitoring starts with the command PIN_StartProgram().

Section 2

INS_AddInstrumentFunction(Instruction, 0); method takes the Instruction function as a function pointer. Our Instruction function should contain the main injection logic. Basically, pin tool inserts pseudo instructions to our application binary and it tracks the output of these injected functions to track the application behavior. How are the instructions injected? Simple; It’s using this section.

The INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END)  inserts our own method called docount. Yes. you guessed it right. AFUNPTR says that it’s a function pointer. This function can have arguments. If it has arguments, you have to specify them in a comma separated fashion. At the end of the arguments, you have to enter IARG_END. Since we do not have any arguments just add IARG_END. ins is the instruction being monitored from our original application (which needs to be profiled). IPOINT_BEFORE says to execute before the instruction is evaluated. You could check intel documentation for other types of flags such as `IPOINT_AFTER` or `
IPOINT_TAKEN_BRANCH`. 

Modification

To count the branches instead of all of the branches, we just have to add an if condition. That’s it. Now the tool counts the number of branches instead of all instructions.

if (INS_IsBranch(ins)) {
    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);
}

Section 3

This is the actual method (docount) that would be inserted to the program execution. Since we need a count, as you can see, each time the function (docount) is called, we just increment the global variable icount.

Modification

Change the variable name to branchcount and method name to dobranchcount. Change the function name in section 2, INS_InsertCall.

// The running count of branch instructions is kept here
// make it static to help the compiler optimize dobranchcount
static UINT64 branchcount = 0;
// This function is called before every instruction is executed
VOID dobranchcount() { branchcount++; }

Section 4

This section specifies the KnobOutputFile. It specifies the output file and this is the line that I skipped in Section 1.  The KnobOutputFile specifies that we can specify the filename using the -o directive. If the file name is not specified, it would default to whatever is given here.

Modification

To avoid replacing results of another tool let’s rename the file.

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool","o", "branchcount.out", "specify output file name");

Section 5

This section specifies what will be written to the output file. You can format your output file content here. Just to be consistent, rename the variable name to branch count instead of Count.

That’s it! You’ve understood and written your tool to count the number of branch instructions. Next let’s compile and run it.

Compiling and Running

Let’s copy the makefile and makefile.rules to our folder Bc. Make tool makes the programmer’s life very easy by keeping track of programs by different sources.

cp /opt/pin-dir/source/tool/ManualExamples/makefile /opt/pin-dir/source/tool/Bc/ 
cp /opt/pin-dir/source/tool/ManualExamples/makefile.rules /opt/pin-dir/source/tool/Bc/

Now you will need to modify the <code>makefile.rules</code> to include our tool’s name. Go to the line, TEST_TOOL_ROOTS := . You will see a list of programs mentioned after the equal sign. Remove all of them and replace it with your tool name. In our case that would be branchcount. Do not include the file extension.

At the end of the file, you will see the lines.  Remove or comment out as below since we do not have this tool now.

#$(OBJDIR)divide_by_zero$(EXE_SUFFIX): divide_by_zero_$(OS_TYPE).c#       $(APP_CC) $(APP_CXXFLAGS_NOOPT) $(COMP_EXE) $(APP_LDFLAGS_NOOPT) $(APP_LIBS)

Leave a Reply

avatar
  Subscribe  
Notify of