A P P E N D I X A |
Profiling Programs With prof, gprof, and tcov |
The tools discussed in this appendix are standard utilities for timing programs and obtaining performance data to analyze, and are called traditional profiling tools. The profiling tools prof and gprof are provided with the Solaris Operating System. tcov is a code coverage tool provided with the Sun compilers and tools.
Note - If you want to track how many times a function is called or how often a line of source code is executed, use the traditional profiling tools. If you want a detailed analysis of where your program is spending time, you can get more accurate information using the Collector and Performance Analyzer. See Chapter 3 and the online help for information on using these tools. |
TABLE A-1 describes the information that is generated by these standard performance profiling tools.
Not all the traditional profiling tools work on modules written in programming languages other than C. See the sections on each tool for more information about languages.
This appendix covers the following topics:
prof generates a statistical profile of the CPU time used by a program and counts the number of times each function in a program is entered. Different or more detailed data is provided by the gprof call-graph profile and the tcov code coverage tools.
To generate a profile report using prof:
1. Compile your program with the -p compiler option.
Profiling data is sent to a profile file called mon.out. This file is overwritten each time you run the program.
3. Run prof to generate a profile report.
The syntax of the prof command is as follows.
Here, program-name is the name of the executable. The profile report is written to stdout. It is presented as a series of rows for each function under these column headings:
The use of prof is illustrated in the following example.
The profile report from prof is shown in the table below:
The profile report shows that most of the program execution time is spent in the compare_strings() function; after that, most of the CPU time is spent in the _strlen() library function. To make this program more efficient, the user would concentrate on the compare_strings() function, which consumes nearly 20% of the total CPU time, and improve the algorithm or reduce the number of calls.
It is not obvious from the prof profile report that compare_strings() is heavily recursive, but you can deduce this by using the call graph profile described in Using gprof to Generate a Call Graph Profile. In this particular case, improving the algorithm also reduces the number of calls.
While the flat profile from prof can provide valuable data for performance improvements, a more detailed analysis can be obtained by using a call graph profile to display a list identifying which modules are called by other modules, and which modules call other modules. Sometimes removing calls altogether can result in performance improvements.
Like prof, gprof generates a statistical profile of the CPU time that is used by a program and it counts the number of times that each function is entered. gprof also counts the number of times that each arc in the program's call graph is traversed. An arc is a caller-callee pair.
To generate a profile report using gprof:
1. Compile your program with the appropriate compiler option.
Profiling data is sent to a profile file called gmon.out. This file is overwritten each time you run the program.
3. Run gprof to generate a profile report.
The syntax of the prof command is as follows.
Here, program-name is the name of the executable. The profile report is written to stdout, and can be large. The report consists of two major items:
The profile report from gprof contains an explanation of what the various parts of the summary mean and identifies the granularity of the sampling, as shown in the following example.
The 4 bytes means resolution to a single instruction. The 0.07% of 14.74 seconds means that each sample, representing ten milliseconds of CPU time, accounts for 0.07% of the run.
The use of gprof is illustrated in the following example.
The following table is part of the call graph profile.
In this example there are 761 lines of data in the input file to the index.assist program. The following conclusions can be made:
The tcov utility gives information on how often a program executes segments of code. It produces a copy of the source file, annotated with execution frequencies. The code can be annotated at the basic block level or the source line level. A basic block is a linear segment of source code with no branches. The statements in a basic block are executed the same number of times, so a count of basic block executions also tells you how many times each statement in the block was executed. The tcov utility does not produce any time-based data.
To generate annotated source code using tcov:
1. Compile your program with the appropriate compiler option.
If you compile with the -a or -xa option you must also link with it. The compiler creates a coverage data file with the suffix .d for each object file. The coverage data file is created in the directory specified by the environment variable TCOVDIR. If TCOVDIR is not set, the coverage data file is created in the current directory.
Note - Programs compiled with -xa (C) or -a (other compilers) run more slowly than they normally would, because updating the .d file for each execution takes considerable time. |
When your program completes, the coverage data files are updated.
3. Run tcov to generate annotated source code.
The syntax of the tcov command is as follows.
Here, source-file-list is a list of the source code filenames. For a list of options, see the tcov(1) man page. The default output of tcov is a set of files, each with the suffix .tcov, which can be changed with the -o filename option.
A program compiled for code coverage analysis can be run multiple times (with potentially varying input); tcov can be used on the program after each run to compare behavior.
The following example illustrates the use of tcov.
This small fragment of the C code from one of the modules of index.assist shows the insert_index_entry() function, which is called recursively. The numbers to the left of the C code show how many times each basic block was executed. The insert_index_entry() function is called 11,152 times.
The tcov utility places a summary like the following at the end of the annotated program listing. The statistics for the most frequently executed basic blocks are listed in order of execution frequency. The line number is the number of the first line in the block.
The following is the summary for the index.assist program:
It is possible to create a tcov profiled shareable library and use it in place of the corresponding library in binaries which have already been linked. Include the -xa (C) or -a (other compilers) option when creating the shareable libraries, as shown in this example.
This command includes a copy of the tcov profiling functions in the shareable libraries, so that clients of the library do not need to relink. If a client of the library is already linked for profiling, then the version of the tcov functions used by the client is used to profile the shareable library.
tcov uses a simple file-locking mechanism for updating the block coverage database in the .d files. It employs a single file, tcov.lock, for this purpose. Consequently, only one executable compiled with -xa (C) or -a (other compilers) should be running on the system at a time. If the execution of the program compiled with the -xa (or -a) option is manually terminated, then the tcov.lock file must be deleted manually.
Files compiled with the -xa or -a option call the profiling tool functions automatically when a program is linked for tcov profiling. At program exit, these functions combine the information collected at runtime for file xyz.f (for example) with the existing profiling information stored in file xyz.d. To ensure this information is not corrupted by several people simultaneously running a profiled binary, a xyz.d.lock lock file is created for xyz.d for the duration of the update. If there are any errors in opening or reading xyz.d or its lock file, or if there are inconsistencies between the runtime information and the stored information, the information stored in xyz.d is not changed.
If you edit and recompile xyz.f the number of counters in xyz.d can change. This is detected if an old profiled binary is run.
If too many people are running a profiled binary, some of them cannot obtain a lock. An error message is displayed after a delay of several seconds. The stored information is not updated. This locking is safe across a network. Since locking is performed on a file-by-file basis, other files may be correctly updated.
The profiling functions attempt to deal with automounted file systems that have become inaccessible. They still fail if the file system containing a coverage data file is mounted with different names on different machines, or if the user running the profiled binary does not have permission to write to either the coverage data file or the directory containing it. Be sure all the directories are uniformly named and writable by anyone expected to run the binary.
The following error messages may be reported by the tcov runtime functions:
Like the original tcov, tcov Enhanced gives line-by-line information on how a program executes. It produces a copy of the source file, annotated to show which lines are used and how often. It also gives a summary of information about basic blocks. tcov Enhanced works with both C and C++ source files.
tcov Enhanced overcomes some of the shortcomings of the original tcov. The improved features of tcov Enhanced are:
To generate annotated source code using tcov Enhanced:
1. Compile your program with the -xprofile=tcov compiler option.
Unlike tcov, tcov Enhanced does not generate any files at compile time.
A directory is created to store the profile data, and a single coverage data file called tcovd is created in that directory. By default, the directory is created in the location where you run the program program-name, and it is called program-name.profile. The directory is also known as the profile bucket. The defaults can be changed using environment variables (see tcov Directories and Environment Variables).
3. Run tcov to generate annotated source code.
The syntax of the tcov command is as follows.
Here, source-file-list is a list of the source code filenames, and option-list is a list of options, which can be obtained from the tcov(1) man page. You must include the -x option to enable tcov Enhanced processing.
The default output of tcov Enhanced is a set of annotated source files whose names are derived by appending .tcov to the corresponding source file name.
The following example illustrates the syntax of tcov Enhanced.
% cc -xprofile=tcov -o index.assist index.assist.c % index.assist % tcov -x index.assist.profile index.assist.c |
The output of tcov Enhanced is identical to the output from the original tcov.
You can create profiled shared libraries for use with tcov Enhanced by including the -xprofile=tcov compiler option, as shown in the following example.
tcov Enhanced uses a simple file-locking mechanism for updating the block coverage data file. It employs a single file created in the same directory as the tcovd file. The file name is tcovd.temp.lock. If execution of the program compiled for coverage analysis is manually terminated, then the lock file must be deleted manually.
The locking scheme does an exponential back-off if there is a contention for the lock. If, after five tries, the tcov runtime cannot acquire the lock, it exits, and the data is lost for that run. In this case, the following message is displayed.
When you compile a program for tcov and run the program, the running program generates a profile bucket. If a previous profile bucket exists, the program uses that profile bucket. If a profile bucket does not exist, it creates the profile bucket.
The profile bucket specifies the directory where the profile output is generated. The name and location of the profile output are controlled by defaults that you can modify with environment variables.
The default profile bucket is named after the executable with a .profile extension and is created in the directory where the executable is run. Therefore, if you run a program called /usr/bin/xyz from /home/userdir, the default behavior is to create a profile bucket called xyz.profile in /home/userdir.
A UNIX process can change its current working directory during the execution of a program. The current working directory used to generate the profile bucket is the current working directory of the program at exit. In the rare case where a program actually does change its current working directory during execution, you can use the environment variables to control where the profile bucket is generated.
You can set the following environment variables to modify the defaults:
Can be used to specify the name of the profile bucket at runtime. The value of this variable is always appended to the value of SUN_PROFDATA_DIR if both variables are set. Doing this may be useful if the name of the executable is not the same as the value in argv[0] (for example, the invocation of the executable was through a symbolic link with a different name).
Can be used to specify the name of the directory that contains the profile bucket. It is used at runtime and by the tcov command.
TCOVDIR is supported as a synonym for SUN_PROFDATA_DIR to maintain backward compatibility. Any setting of SUN_PROFDATA_DIR causes TCOVDIR to be ignored. If both SUN_PROFDATA_DIR and TCOVDIR are set, a warning is displayed when the profile bucket is generated.
TCOVDIR is used at runtime and by the tcov command.
Copyright © 2004, Sun Microsystems, Inc. All rights reserved.