C++生成覆盖率之gcov

下面会介绍一个C++生成覆盖率的例子。

一. 源码

#include

char Visit[51];

int Ans[51];

int N;

int Cnt[11];

 

void ForEmptyCheck() {

 

    puts("Here");

 

}

 

int Sum() {

 

    int i, j, Sum = 0;

 

    for (i = 0; i < N; ++i) {

 

        int min = Ans[i];

 

        for (j = i; j < N; ++j) {

 

            if (Ans[j] < min) {

 

                min = Ans[j];

 

            }

 

        }

 

        Sum += min;

 

    }

 

    ++Cnt[Sum];

 

    return Sum;

 

}

 

void DFS(int s, int cnt) {

 

    int i;

 

    char over = 1;

 

    Visit[s] = 1;

 

    Ans[cnt] = s + 1;

 

    for (i = 0; i < N; ++i) {

 

        if (!Visit[i]) {

 

            over = 0;

 

            DFS(i, cnt + 1);

 

            Visit[i] = 0;

 

        }

 

    }

 

    if (over) {

 

        for (i = 0; i < N; ++i) {

 

            printf("%d ", Ans[i]);

 

        }

 

        printf("\t%d\n", Sum());

 

    }

 

}

 

int main() {

 

    int i;

 

    N = 4;

 

    for (i = 0; i < N; ++i) {

 

        DFS(i, 0);

 

        Visit[i] = 0;

 

    }

 

    for (i = 4; i <= 10; ++i) {

 

        printf("%d ", Cnt[i]);

 

    }

 

    puts("");

 

    return 0;

 

}

二. 编译、链接、执行可执行文件

$ gcc -o test -coverage test.c -lgcov
$ ./test

$ ls

三.分析目标文件

$ gcov test.c

$ 查看test.c.gcov

  -:    0:Source:test.c

 

    -:    0:Graph:test.gcno

 

    -:    0:Data:test.gcda

 

    -:    0:Runs:1

 

    -:    0:Programs:1

 

    -:    1:#include

 

    -:    2:

 

    -:    3:char Visit[51];

 

    -:    4:int Ans[51];

 

    -:    5:int N;

 

    -:    6:int Cnt[11];

 

    -:    7:

 

#####:    8:void ForEmptyCheck() {

 

#####:    9:    puts("Here");

 

#####:   10:}

 

   24:   11:int Sum() {

 

   24:   12:    int i, j, Sum = 0;

 

  120:   13:    for (i = 0; i < N; ++i) {

 

   96:   14:        int min = Ans[i];

 

  336:   15:        for (j = i; j < N; ++j) {

 

  240:   16:            if (Ans[j] < min) {

 

   58:   17:                min = Ans[j];

 

    -:   18:            }

 

    -:   19:        }

 

   96:   20:        Sum += min;

 

    -:   21:    }

 

   24:   22:    ++Cnt[Sum];

 

   24:   23:    return Sum;

 

    -:   24:}

 

   64:   25:void DFS(int s, int cnt) {

 

    -:   26:    int i;

 

   64:   27:    char over = 1;

 

   64:   28:    Visit[s] = 1;

 

   64:   29:    Ans[cnt] = s + 1;

 

  320:   30:    for (i = 0; i < N; ++i) {

 

  256:   31:        if (!Visit[i]) {

 

   60:   32:            over = 0;

 

   60:   33:            DFS(i, cnt + 1);

 

   60:   34:            Visit[i] = 0;

 

    -:   35:        }

 

    -:   36:    }

 

   64:   37:    if (over) {

 

  120:   38:        for (i = 0; i < N; ++i) {

 

   96:   39:            printf("%d ", Ans[i]);

 

    -:   40:        }

 

   24:   41:        printf("\t%d\n", Sum());

 

    -:   42:    }

 

   64:   43:}

 

    1:   44:int main() {

 

    -:   45:    int i;

 

    1:   46:    N = 4;

 

    5:   47:    for (i = 0; i < N; ++i) {

 

    4:   48:        DFS(i, 0);

 

    4:   49:        Visit[i] = 0;

 

    -:   50:    }

 

    8:   51:    for (i = 4; i <= 10; ++i) {

 

    7:   52:        printf("%d ", Cnt[i]);

 

    -:   53:    }

 

    1:   54:    puts("");

 

    1:   55:    return 0;

 

    -:   56:}

8~10行前面的#是说这几行没有执行到;减号对应的行是说这行没有指令;11行前面的24,是说这行被执行了24次。

四. gcov使用说明

 1. 使用步奏:

      gcov主要是用来生成覆盖率统计数据*.gcov(后续可以使用lcov分析*.gcov来生成html进行展示),使用有三个步奏:

  • 编译阶段,加入编译选项:

    gcc -o test -coverage test.c -lgcov

    生成记录程序流程图等信息: test.gcno

  • 数据收集与提取阶段:./test:

    生成具体的运行信息,这一阶段生成的数据信息自动保存的-o文件所在的目录,包括test.gcda

  • 生成数据报告:gcov hello.c

    生成test.c.gcov

2. 注意事项:

  1. 在编译时不要加优化选项,因为加了优化选项后,代码会发生变化,这样就找不到哪些是自己写的热点代码了;

  2. 如果代码中使用复杂的宏,比如说,这个宏展开后,是循环后者其它控制结构,gcov只在宏调用出现的那一行报告,如果复杂的宏看起来像函数,可以用内联函数来代替;

  3. 代码在编写时要注意,每一行最好只有一条语句;

  4. 可以使用gcov,lcov测试linux内核覆盖率,参考:http://ltp.sourceforge.net/coverage/gcov.php,这里只讨论应用程序的覆盖率。