(转)gcov-代码覆盖分析工具

gcov是一个分析代码覆盖率的工具,包括语句覆盖、分支覆盖。它可以报告每一行语句的执行次数、每个分支的执行概率。

gcov程序调用的格式为:
gcov [options] sourcefilelist

待分析的程序源码:bubblesort.cpp
#include <stdio.h>
void bubbleSort(int list[], int size)
{
    int i, j, temp, swap = 1;

    while (swap)
    {
        swap = 0;

        for (i = (size - 1); i >= 0; i--)
        {
            for (j = 1; j <= i; j++)
            {
                if (list[j - 1] > list[j])
                {
                    temp = list[j - 1];
                    list[j - 1] = list[j];
                    list[j] = temp;
                    swap = 1;
                }
            }
        }
    }
}
void func()
{
    int i, total;
    
    total = 0;
    
    for (i = 0; i < 10; i++)
        total += i;
    
    if (total != 45)
        printf ("Failure/n");
    else
        printf ("Success/n");
}
int main()
{
    int theList[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    int i;

    /* Invoke the bubble sort algorithm */
    bubbleSort(theList, 10);

    /* Print out the final list */
    for (i = 0; i < 10; i++)
    {
        printf("%d\n", theList[i]);
    }
    
    func();

    return 0;
}

编译:g++ -g -Wall -ftest-coverage -fprofile-arcs -o bubblesort bubblesort.cpp。生成.gcno文件(gcov note文件)
运行:./bubblesort。生成.gcda文件(gcov data文件)
分析:gcov bubblesort.cpp。生成.cpp.gcov文件
查看报告:more bubblesort.cpp.gcov。每行语句前面的数字就是该语句的执行次数,如下:
        -:    0:Source:bubblesort.cpp
        -:    0:Graph:bubblesort.gcno
        -:    0:Data:bubblesort.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        1:    2:void bubbleSort(int list[], int size)
        -:    3:{
        1:    4:    int i, j, temp, swap = 1;
        -:    5:
        4:    6:    while (swap)
        -:    7:    {
        2:    8:        swap = 0;
        -:    9:
       22:   10:        for (i = (size - 1); i >= 0; i--)
        -:   11:        {
      110:   12:            for (j = 1; j <= i; j++)
        -:   13:            {
       90:   14:                if (list[j - 1] > list[j])
        -:   15:                {
       45:   16:                    temp = list[j - 1];
       45:   17:                    list[j - 1] = list[j];
       45:   18:                    list[j] = temp;
       45:   19:                    swap = 1;
        -:   20:                }
        -:   21:            }
        -:   22:        }
        -:   23:    }
        1:   24:}
        1:   25:void func()
        -:   26:{
        -:   27:    int i, total;
        -:   28:    
        1:   29:    total = 0;
        -:   30:    
       11:   31:    for (i = 0; i < 10; i++)
       10:   32:        total += i;
        -:   33:    
        1:   34:    if (total != 45)
    #####:   35:        printf ("Failure/n");
        -:   36:    else
        1:   37:        printf ("Success/n");
        1:   38:}
        1:   39:int main()
        -:   40:{
        1:   41:    int theList[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
        -:   42:    int i;
        -:   43:
        -:   44:    /* Invoke the bubble sort algorithm */
        1:   45:    bubbleSort(theList, 10);
        -:   46:
        -:   47:    /* Print out the final list */
       11:   48:    for (i = 0; i < 10; i++)
        -:   49:    {
       10:   50:        printf("%d\n", theList[i]);
        -:   51:    }
        -:   52:    
        1:   53:    func();
        -:   54:
        1:   55:    return 0;
        -:   56:}

可以看到每行代码的执行次数,如第12行代码执行了110次。没有执行的行被标记为#####,如第35行代码。

gcov -b bubblesort.cpp的输出如下:
        -:    0:Source:bubblesort.cpp
        -:    0:Graph:bubblesort.gcno
        -:    0:Data:bubblesort.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include <stdio.h>
function _Z10bubbleSortPii called 1 returned 100% blocks executed 100%
        1:    2:void bubbleSort(int list[], int size)
        -:    3:{
        1:    4:    int i, j, temp, swap = 1;
        -:    5:
        4:    6:    while (swap)
branch  0 taken 67%
branch  1 taken 33% (fallthrough)
        -:    7:    {
        2:    8:        swap = 0;
        -:    9:
       22:   10:        for (i = (size - 1); i >= 0; i--)
branch  0 taken 91%
branch  1 taken 9% (fallthrough)
        -:   11:        {
      110:   12:            for (j = 1; j <= i; j++)
branch  0 taken 82%
branch  1 taken 18% (fallthrough)
        -:   13:            {
       90:   14:                if (list[j - 1] > list[j])
branch  0 taken 50% (fallthrough)
branch  1 taken 50%
        -:   15:                {
       45:   16:                    temp = list[j - 1];
       45:   17:                    list[j - 1] = list[j];
       45:   18:                    list[j] = temp;
       45:   19:                    swap = 1;
        -:   20:                }
        -:   21:            }
        -:   22:        }
        -:   23:    }
        1:   24:}
function _Z4funcv called 1 returned 100% blocks executed 86%
        1:   25:void func()
        -:   26:{
        -:   27:    int i, total;
        -:   28:    
        1:   29:    total = 0;
        -:   30:    
       11:   31:    for (i = 0; i < 10; i++)
branch  0 taken 91%
branch  1 taken 9% (fallthrough)
       10:   32:        total += i;
        -:   33:    
        1:   34:    if (total != 45)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:   35:        printf ("Failure/n");
call    0 never executed
        -:   36:    else
        1:   37:        printf ("Success/n");
call    0 returned 100%
        1:   38:}
function main called 1 returned 100% blocks executed 100%
        1:   39:int main()
        -:   40:{
        1:   41:    int theList[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
        -:   42:    int i;
        -:   43:
        -:   44:    /* Invoke the bubble sort algorithm */
        1:   45:    bubbleSort(theList, 10);
call    0 returned 100%
        -:   46:
        -:   47:    /* Print out the final list */
       11:   48:    for (i = 0; i < 10; i++)
branch  0 taken 91%
branch  1 taken 9% (fallthrough)
        -:   49:    {
       10:   50:        printf("%d\n", theList[i]);
call    0 returned 100%
        -:   51:    }
        -:   52:    
        1:   53:    func();
call    0 returned 100%
        -:   54:
        1:   55:    return 0;
        -:   56:}
可以看到每个while、for、if语句都会引入分支,有时候需要参考汇编才能理解分支点在哪里。

注意:
1,gcov是基于gcc编译器的覆盖率测试的程序,它只支持gcc。
2,对于单元测试来说,Test Harness程序(包括stubs、driver)需要自己手动编写,当然测试用例(Test Suites)更需要你自己来写,gcov能够做得,只是帮助你统计覆盖信息。
3,如果你想使用gcov,在代码编写时就要有所注意,其中之一就是“每一行只有一条语句”,具体讲,什么算一条语句呢?
 ——注释不算语句
 ——声明算语句,如UNIT x; UNIT y; is not allowed
 ——混合的语句不允许 如{x =1; y=2; } is not allowd
                      while(x<MAX) { y = 2} is not allowed
 ... ...
 为什么呢?因为gcov的结果是以“行”来统计的。如果一行执行语句太多,不便于结果的分析。
4,如果你代码中使用复杂的宏,比如说这个宏展开后是循环或者其他控制结构,这样的话gcov的结果对你的帮助一般不会太大,因为gcov只在宏调用出现的那一行报告。
  如果复杂的宏看起来像函数,你应该用内联函数解决这个问题。
5,要想更好的度量进而调优你的程序的性能,gcov应该和gprof配合使用。二者协作,可以给出
每一行代码执行的次数   how often each line of code executes
那些代码行被执行过     what lines of code are actually executed
每块代码计算时间是多少  how much computing time each section of code uses
6,图形化工具:lcov genhtml
7,.gcno和.gcda文件是特定格式的二进制文件,可以用gcov-dump工具来查看

gcov的选项:
-a, --all-blocks
在.gcov文件中输出每个基本快(basic block)的执行次数。如果没有-a选项,则输出'main'函数这个block的执行次数
-b, --branch-probabilities
在.gcov文件中输出每个分支的执行概率,并有分支统计信息。
-c, --branch-counts
-c是默认选项,打印各个语句的调用次数
-f 查看函数级覆盖度,-f选项可以和-b选项一起使用得到以函数为单位的分支覆盖率。

gcov没有提供多个文件报告汇总的功能。

你可能感兴趣的:((转)gcov-代码覆盖分析工具)