下面会介绍一个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. 注意事项:
-
在编译时不要加优化选项,因为加了优化选项后,代码会发生变化,这样就找不到哪些是自己写的热点代码了;
-
如果代码中使用复杂的宏,比如说,这个宏展开后,是循环后者其它控制结构,gcov只在宏调用出现的那一行报告,如果复杂的宏看起来像函数,可以用内联函数来代替;
-
代码在编写时要注意,每一行最好只有一条语句;
-
可以使用gcov,lcov测试linux内核覆盖率,参考:http://ltp.sourceforge.net/coverage/gcov.php,这里只讨论应用程序的覆盖率。