How to Profile a C program in Linux using GNU gprof

Performance is one of the biggest challenges programmers face while developing software. That is the reason why code profiling is one of the most important aspects of software development, as it lets you identify bottlenecks, dead code, and even bugs. If you are a programmer who develops software applications for Linux, the GNU profiler “gprof” is the tool to look out for.

Gprof comes pre-installed with most of the Linux distributions, but if that’s not the case with your Linux distro, you can download and install it through a command line package manager like apt-get or yum. For example, run the following command to download and install gprof on Debian-based systems:

sudo apt-get install binutils

Before you use gprof to generate profiling data, make sure that your program executable contains extra information required by the profiler to function properly. This can be achieved by adding the -pg command line option while compiling your code, assuming that you are using the gcc compiler. If you are using separate commands for compiling and linking, add the command line option to both the commands.

Consider the following C program as an example:

#include <stdio.h>
 
void func2()
{
   int count = 0;
   for(count=0; count < 0XFFFFF; count++);
 
   return;
}
 
void func1(void)
{
   int count = 0;
   for(count=0; count < 0XFF; count++)
       func2();
 
   return;
}
 
int main(void)
{
    printf("\n Hello World! \n");
    func1();
    func2();
    return 0;
}

As described in the previous section, compile the code with the -pg option:

gcc -Wall -pg test.c -o test

Once compiled, run the program:

 ./test

After successful execution, the program will produce a file named “gmon.out” that contains the profiling information, but in a raw form, which means that you cannot open the file and directly read the information. To generate a human readable file, run the following command:

gprof test gmon.out > prof_output

This command writes all the profiling information in human readable format to “prof_output” file. Note that you can change the output file name as per your convenience.

If you open the file containing profiling data, you’ll see that the information is divided into two parts: Flat profile and Call graph. While the former contains details like function call counts, total execution time spent in a function, and more, the latter describes the call tree of the program, providing details about the parent and child functions of a particular function.

For example, the following is the Flat profile in our case:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
100.00      0.94     0.94      256     3.67     3.67  func2
  0.00      0.94     0.00        1     0.00   936.33  func1

The below is the Call graph:

index % time    self  children    called     name
                0.00    0.00       1/256         main [2]
                0.94    0.00     255/256         func1 [3]
[1]    100.0    0.94    0.00     256         func2 [1]
-----------------------------------------------
 
[2]    100.0    0.00    0.94                 main [2]
                0.00    0.94       1/1           func1 [3]
                0.00    0.00       1/256         func2 [1]
-----------------------------------------------
                0.00    0.94       1/1           main [2]
[3]     99.6    0.00    0.94       1         func1 [3]
                0.94    0.00     255/256         func2 [1]
-----------------------------------------------

Note that the detailed explanation of these fields is present in the file containing profiling information (prof_output in this case) and is generated each time the profiler is run. To turn off the details, use the -b command line option with the gprof command.

  • To write the gmon.out file properly, your program must exit normally. The file is not produced when the program either exits by calling the _exit() function or abnormally terminates due to an un-handled signal.
  • The “gmon.out” file is always created in the current working directory. So, make sure that your program has sufficient privileges to create a file in the current directory.
  • An external tool by the name of gprof2dot can be used to convert the call graph from gprof into graphical form.
  • Using gprof, you can also produce an annotated source listing that gives an idea about the number of times each line of the program was executed. To produce this information, compile the program with -g (along with the -pg option explained earlier) and run the gprof command with the -A command line option.