10.3 Coverage testing with gcov
The GNU coverage testing tool gcov
analyses the number of times
each line of a program is executed during a run. This makes it possible
to find areas of the code which are not used, or which are not exercised
in testing. When combined with profiling information from gprof
the information from coverage testing allows efforts to speed up a
program to be concentrated on specific lines of the source code.
We will use the example program below to demonstrate gcov
. This
program loops overs the integers 1 to 9 and tests their divisibility
with the modulus (%
) operator.
#include <stdio.h>
int
main (void)
{
int i;
for (i = 1; i < 10; i++)
{
if (i % 3 == 0)
printf ("%d is divisible by 3\n", i);
if (i % 11 == 0)
printf ("%d is divisible by 11\n", i);
}
return 0;
}
To enable coverage testing the program must be compiled with
the following options:
$ gcc -Wall -fprofile-arcs -ftest-coverage cov.c
This creates an instrumented executable which contains additional
instructions that record the number of times each line of the program is
executed. The option -ftest-coverage
adds instructions for
counting the number of times individual lines are executed, while
-fprofile-arcs
incorporates instrumentation code for each
branch of the program. Branch instrumentation records how frequently
different paths are taken through 'if' statements and other
conditionals. The executable must then be run to create the coverage
data:
$ ./a.out
3 is divisible by 3
6 is divisible by 3
9 is divisible by 3
The data from the run is written to several files with the extensions
'.bb' '.bbg' and '.da' respectively in the current
directory. This data can be analyzed using the gcov
command and
the name of a source file:
$ gcov cov.c
88.89% of 9 source lines executed in file cov.c
Creating cov.c.gcov
The gcov
command produces an annotated version of the original
source file, with the file extension '.gcov', containing counts of
the number of times each line was executed:
#include <stdio.h>
int
main (void)
{
1 int i;
10 for (i = 1; i < 10; i++)
{
9 if (i % 3 == 0)
3 printf ("%d is divisible by 3\n", i);
9 if (i % 11 == 0)
###### printf ("%d is divisible by 11\n", i);
9 }
1 return 0;
1 }
The line counts can be seen in the first column of the output. Lines
which were not executed are marked with hashes '######'. The
command 'grep '######' *.gcov' can be used to find parts of a
program which have not been used.