覆盖率测试工具gcov的前端工具_LCOV_简介

1、Gcov是进行代码运行的覆盖率统计的工具,它随着gcc的发布一起发布的,它的使用也很简单,需要在编译和链接的时候加上-fprofile-arcs -ftest-coverage生成二进制文件,gcov主要使用.gcno和.gcda两个文件,.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。.gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其他的概要信息。gcda文件的生成需要先执行可执行文件才能生成。生成gcda文件之后执行命令gcov *.cpp就会在屏幕上打印出测试的覆盖率,并同时生成文件“*cpp.gcov”,然后用vi打开就可以看见哪行被覆盖掉了。

 

2、lcov的安装很简单,下载源码执行make install就可以了,在生成的“*.cpp.gcov"文件中执行lcov --directory  .   --capture --output-file app.info生成info文件,再执行genhtml  -o  results  app.info就会生成result目录,生成的html文件就在result目录下

___________________________

http://www.linuxidc.com/Linux/2011-05/36544.htm

Content

1. Lcov是什么?

2. 如何在Linux平台安装Lcov?

3. 如何使用Lcov?

(1) 使用lcov收集覆盖率数据并写入文件

(2) 使用genhtml生成基于HTML的输出

(3) 该例子的图形显示

4. 编译lcov自带例子

5. 其他相关工具

(1) gcov-dump

(2) ggcov

 

 

1. Lcov是什么?


是GCOV图形化的前端工具
是Linux Test Project维护的开放源代码工具,最初被设计用来支持Linux内核覆盖率的度量
基于Html输出,并生成一棵完整的HTML树
输出包括概述、覆盖率百分比、图表,能快速浏览覆盖率数据
支持大项目,提供三个级别的视图:目录视图、文件视图、源码视图

Use lcov to collect coverage data and genhtml to create HTML pages. Coverage data can either be collected from the currently running Linux kernel or from a user space application. To do this, you  have  to  complete the following preparation steps:

 

For Linux kernel coverage:

  Follow  the setup instructions for the gcov-kernel infrastructure:

http://ltp.sourceforge.net/coverage/gcov.php

 

For user space application coverage:

  Compile the application with GCC using the options "-fprofile-arcs" and "-ftest-coverage".

 

2. 如何在Linux平台安装Lcov?

# wget http://downloads.sourceforge.net/ltp/lcov-1.9.tar.gz

# tar -zxvf lcov-1.9.tar.gz

# cd lcov-1.9

# ls

bin      contrib  descriptions.tests  lcovrc    man     rpm

CHANGES  COPYING  example             Makefile  README

# make install

不需要编译,直接安装即可,lcov, gendesc, genhtml, geninfo, genpng将被安装到/usr/bin目录。

 

3. 如何使用Lcov?

 

以Linux平台代码覆盖率测试工具GCOV简介一文的例子为例。

 

(1) 使用lcov收集覆盖率数据并写入文件 

# lcov --capture --directory . --output-file test.info --test-name test

Capturing coverage data from .

Found gcov version: 4.1.2

Scanning . for .gcda files ...

Found 1 data files in .

Processing test.gcda

Finished .info-file creation

.表示当前目录,收集coverage data,即.gcda文件中的信息,并写入test.info文件,且取名为test。其他选项请参考lcov的manual页。

 

test.info文件内容如下。

TN:test

SF:/home/zubo/gcc/2011-04-10.sample/test.c

FN:4,main

FNDA:1,main

FNF:1

FNH:1

BRDA:9,2,0,10

BRDA:9,2,1,1

BRDA:12,0,0,0

BRDA:12,0,1,1

BRF:4

BRH:3

DA:4,1

DA:7,1

DA:9,11

DA:10,10

DA:12,1

DA:13,0

DA:15,1

DA:16,1

LF:8

LH:7

end_of_record

(2) 使用genhtml生成基于HTML的输出


# genhtml test.info --output-directory output --title "a simple test" --show-details --legend

Reading data file test.info

Found 1 entries.

Found common filename prefix "/home/zubo"

Writing .css and .png files.

Generating output.

Processing file gcc/2011-04-10.sample/test.c

Writing directory view page.

Overall coverage rate:

  lines......: 87.5% (7 of 8 lines)

  functions..: 100.0% (1 of 1 function)

  branches...: 75.0% (3 of 4 branches)

选项解释请参考genhtml的manual页。cd到output目录,可以看到,生成了很多相关文件,如下。


# cd output

# ls

amber.png    gcov.css    index-sort-b.html  ruby.png

emerald.png  glass.png   index-sort-f.html  snow.png

gcc          index.html  index-sort-l.html  updown.png

(3) 该例子的图形显示

 

(3.1) top level的视图

 覆盖率测试工具gcov的前端工具_LCOV_简介_第1张图片

 

(3.2) 文件或函数的视图

 覆盖率测试工具gcov的前端工具_LCOV_简介_第2张图片

4. 编译lcov自带例子

 

# cd /usr/src/lcov-1.9/example

# make

 

编译、运行自带例子并查看结果是快速学习某个工具最好的方法。从example的makefile文件和编译输出,都可以学习相关概念和命令的使用方法。Html输出可以由/usr/src/lcov-1.9/example/output/index.html查看。读者可自行实验。

 

5. 其他相关工具

 

(1) gcov-dump

 

或许,我们还可以使用gcov-dump命令输出gcov的相关数据,但gcc默认不编译gcov-dump,因此,要使用它,可能需要重新编译gcc。

 

(2) ggcov

 

Ggcov is a Graphical tool for displaying gcov test coverage data. 详细信息可参考http://ggcov.sourceforge.net。

 

 

Reference

lcov的manual页

genhtml的manual页

geninfo的manual页

lcov的readme文件,本文/usr/src/lcov-1.9/README

lcov的makefile文件,本文为/usr/src/lcov-1.9/Makefile

 

本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-05/36544.htm

 

 

*************************

代码覆盖率——gcov lcov的使用

一、关于gcov工具
gcov伴随gcc 发布。gcc编译加入-fprofile-arcs -ftest-coverage 参数生成二进制程序,执行测试用例生成代码覆盖率信息。
1、如何使用gcov
用GCC编译的时候加上-fprofile-arcs -ftest-coverage选项,链接的时候也加上。
fprofile-arcs参数使gcc创建一个程序的流图,之后找到适合图的生成树。只有不在生成树中的弧被操纵(instrumented):gcc添加了代码来清点这

些弧执行的次数。当这段弧是一个块的唯一出口或入口时,操纵工具代码(instrumentation code)将会添加到块中,否则创建一个基础块来包含操纵

工具代码。gcov主要使用.gcno和.gcda两个文件。
.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。
.gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其他的概要信息。
Gcov执行函数覆盖、语句覆盖和分支覆盖。

举个例子,程序代码由main.c和tmp.c两个文件组成,编译、链接、运行程序
编译:gcc -fprofile-arcs -ftest-coverage -o myapp main.c tmp.c
运行:./myapp
然后 输入
命令: gcov main.c,gcov tmp.c

这个时候当前目录下有了新的文档main.c.gcov,和tmp.c.gcov
若想保存覆盖率文件,上述命令修改为:
命令:

gcov main.c >>yourfilename,

gcov tmp.c >>yourfilename

查看结果:
        -:   65:/***************************************************************************************
        -:   66: * name         : main
        -:   67: * return       : 0 OK
        -:   68: *                other ERROR
        -:   69: * history      : 2006-06-13
        -:   70:****************************************************************************************/
        -:   71:int main( int argc, char *argv[] )                                                      /* the entrance for program

*/
function main called 4 returned 100% blocks executed 81%
        4:   72:{
        4:   73:        int loop = 0 ;
        4:   74:        int ret = OK ;
        4:   75:        int empty_line = 0 ;
        4:   76:        int code_line = 0 ;
        4:   77:        int annotation_line = 0 ;
        4:   78:        struct stat file_stat ;                                                         /* use for file state */
        4:   79:        char recu_name[256] ;
        4:   80:        char *pwd = NULL ;
        4:   81:        char *tmp = NULL ;
        -:   82:
        4:   83:        if( argc = MAX_FILE ){                                    /* file size larger than max size */
    #####:   98:                        printf( "file [%s] size is over 64K! \ncontinue....\n", argv[loop] ) ;
    #####:   99:                        continue ;
        -: 100:                }

##### 这就是表示没跑到的

   
各个参数使用如下:    
gcov [-b] [-c] [-v] [-n] [-l] [-f] [-o directory] sourcefile
-b
    Write branch frequencies to the output file, and write branch summary info to the standard output. This option allows you to

see how often each branch in your program was taken.
    //b(ranch),分支测试
-c
    Write branch frequencies as the number of branches taken, rather than the percentage of branches taken.
-v
    Display the gcov version number (on the standard error stream).
    //太简单了吧,我上面用了
-n
    Do not create the gcov output file.
-l
    Create long file names for included source files. For example, if the header file `x.h' contains code, and was included in the

file `a.c', then running gcov on the file `a.c' will produce an output file called `a.c.x.h.gcov' instead of `x.h.gcov'. This can

be useful if `x.h' is included in multiple source files.
-f
    Output summaries for each function in addition to the file level summary.
-o
    The directory where the object files live. Gcov will search for `.bb', `.bbg', and `.da' files in this directory.
新版的是这么说的
     -o directory│file
       --object-directory directory
       --object-file file
           Specify either the directory containing the gcov data files, or the
           object path name. The .gcno, and .gcda data files are searched for
           using this option. If a directory is specified, the data files are
           in that directory and named after the source file name, without its
           extension. If a file is specified here, the data files are named
           after that file, without its extension. If this option is not sup-
           plied, it defaults to the current directory.
其他的更有新版的-u,
     -u
       --unconditional-branches
           When branch counts are given, include those of unconditional
           branches. Unconditional branches are normally not interesting.
      -p
       --preserve-paths
           Preserve complete path information in the names of generated .gcov
           files. Without this option, just the filename component is used.
           With this option, all directories are used, with ’/’ characters
           translated to ’#’ characters, ’.’ directory components removed and
           ’..’ components renamed to ’^’. This is useful if sourcefiles are
           in several different directories. It also affects the -l option.
  

二、关于lcov

Lcov则是上的gcov 结果展现的一个前端,可以将覆盖率信息转换成html展现。
1、如何使用lcov
Makefile 在编译和link环节都加入 -fprofile-arcs -ftest-coverage 选项     

收集覆盖率数据生成app.info文件
命令:cov --directory .   --capture --output-file myapp.info
Capturing coverage data from .
Found gcov version: 3.4.6
Scanning . for .gcda files ...
Found 1 data files in .
Processing ./TestQuery.gcda
Finished .info-file creation

转换成html格式
命令:genhtml -o results app.info
Reading data file app.info
Found 18 entries.
Found common filename prefix "/home/search/isearch_yb/src"
Writing .css and .png files.
Generating output.
Processing file cpp/core/basis/GlobalDef.h
Processing file cpp/core/search/QueryCache.h
...
Writing directory view page.
Overall coverage rate: 117 of 514 lines (22.8%)

2、查看html文件
html包含代码覆盖的详细信息

更多命令选项

http://ltp.sourceforge.net/coverage/lcov/lcov.1.php?PHPSESSID=26d7173d1f492f5f691715ef8b7d0b40

参考资料
1、http://ltp.sourceforge.net/coverage/

*******************

Gcov作为gnu/gcc工作组件之一,是一款的免费的代码覆盖率测试工具,而且可以结合lcov生成美观的html的测试报表。本文介绍一些gcov的使用方法,基本原理,一些实际中可能会遇到的问题以及解决思路。

  1. Gcov的用法

1.1       编译

Gcov的使用方法很简单,首先需要给gcc编译的时候打开覆盖测试的开关

例如要对srcfile.c单个文件生成的程序进行代码覆盖测试,在gcc编译的时候:

1
2
                    
gcc -fprofile-arcs -ftest-coverage srcfile.c -o srcfile

或者简化成:

1
2
                    
gcc --coverage srcfile.c -o srcfile

如果源文件很多,需要编译,链接的时候,在gcc编译的时候:

编译:

1
2
                             
gcc -fprofile-arcs -ftest-coverage -c srcfile.c

链接:

1
2
                             
gcc srcfile.o -o srcfile -lgcov

或者

1
2
                            
gcc srcfile.o –o srcfile -fprofile-arcs

看出来了没有,gcov可以只针对大项目中的某几个单独的文件进行代码覆盖测试,只要在这几个文件编译的时候,加上-ftest-coverage,其他的文件不变就行了,爽吧。

1.2       生成报表

编译完成后会同时生成 *.gcno 文件(gcov notes),gcov生成覆盖率报告时需要参考该文件。

运行生成的可执行文件,给予正常的工作负载,待其正常退出后会生成覆盖率统计数据 *.gcda 文件(gcov data)

通过如下命令行之一查看覆盖率报告:

gcov 生成文本统计结果和带 line-count 标注的源代码:gcov srcfile

lcov 生成较正式的 HTML 报告:

1
2
lcov -c -d srcfile_dir -o srcfile.info
genhtml -o report_dir srcfile.info

注意:另外,编译选项中最好加入 -g3 -O0,前者是为了增加调试信息,后者是为了禁用优化,免得覆盖率测试不准确。

1.3       一个单文件的例子

一个例子程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char * argv[]) {
     int i = 0;
     printf ( "Begin Test...\n" );
     if (1 == argc) {
         printf ( "argc == 1\n" );
     } else {
         printf ( "argc != 1\n" );
         for (i = 0; i < argc; i++)
         printf ( "%d\tof\t%d\n" , i+1, argc);
     }
     printf ( "End Test!\n" );
}

编译:

1
gcc test .c -fprofile-arcs -ftest-coverage -o test

生成文件如下:

1
test  test .c  test .gcno

运行:

1
./test  1  2  3  4

生成文件如下:

1
test  test .c  test .gcda  test .gcno

生成覆盖测试报告:

1
gcov  test

生成的test.gcov如下:

第一列是覆盖情况,第二列是行号加源程序,其中第一列中数字开头的是执行的次数,####开头的是没有执行到的语句。

2. Gcov的实现原理简介

Gcc中指定-ftest-coverage 等覆盖率测试选项后,gcc 会:

  • 在输出目标文件中留出一段存储区保存统计数据
  • 在源代码中每行可执行语句生成的代码之后附加一段更新覆盖率统计结果的代码
  • 在最终可执行文件中进入用户代码 main 函数之前调用 gcov_init 内部函数初始化统计数据区,并将gcov_exit 内部函数注册为 exit handlers
  • 用户代码调用 exit 正常结束时,gcov_exit 函数得到调用,其继续调用 __gcov_flush 函数输出统计数据到 *.gcda 文件中

2 对后台服务程序进行覆盖率测

从 gcc coverage test 实现原理可知,若用户进程并非调用 exit 正常退出,覆盖率统计数据就无法输出,也就无从生成报告了。后台服务程序若非专门设计,一旦启动就很少主动退出,用 kill 杀死进程强制退出时就不会调用 exit,因此没有覆盖率统计结果产生。

为了解决这个问题,我们可以给待测程序增加一个 signal handler,拦截 SIGHUP、SIGINT、SIGQUIT、SIGTERM 等常见强制退出信号,并在 signal handler 中主动调用 exit 或 __gcov_flush 函数输出统计结果即可。如何使用gcov完成对后台驻守程序的测试

该方案仍然需要修改待测程序代码,不过借用动态库预加载技术和 gcc 扩展的 constructor 属性,我们可以将 signalhandler 和其注册过程都封装到一个独立的动态库中,并在预加载动态库时实现信号拦截注册。这样,就可以简单地通过如下命令行来实现异常退出时的统计结果输出了:

1
LD_PRELOAD=./gcov_out.so ./daemon

测试完毕后可直接 kill 掉 daemon 进程,并获得正常的统计结果文件 *.gcda。

用来预加载的动态库gcov_out.so的代码如下,其中__attribute__ ((constructor))

是gcc的符号,它修饰的函数会在main函数执行之前调用,我们利用它把异常信号拦截到我们自己的函数中,然后调用__gcov_flush()输出错误信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#define SIMPLE_WAY
void sighandler( int signo)
{
#ifdef SIMPLE_WAY
     exit (signo);
#else
     extern void __gcov_flush();
     // flush out gcov stats data
     __gcov_flush();
     // raise the signal again to crash process
     raise (signo);
#endif
}
__attribute__ ((constructor))
void ctor()
{
     int sigs[] = {
         SIGILL, SIGFPE, SIGABRT, SIGBUS,
         SIGSEGV, SIGHUP, SIGINT, SIGQUIT,
         SIGTERM
     };
     int i;
     struct sigaction sa;
     sa.sa_handler = sighandler;
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = SA_RESETHAND;
     for (i = 0; i < sizeof (sigs)/ sizeof (sigs[0]); ++i) {
         if (sigaction(sigs[i], &sa, NULL) == -1) {
             perror ( "Could not set signal handler" );
         }
     }
}

编译:

1
gcc -shared -fPIC gcov_out.c -o gcov_out.so

4. 参考资料

man gcc

man gcov

lcov – http://ltp.sourceforge.net/coverage/lcov.php

注意,lcov 最好使用 1.9 及以上版本,否则可能遇到如下错误:

geninfo: ERROR: …: reached unexpected end of file

http://www.linezing.com/blog/?p=234

你可能感兴趣的:(覆盖率测试工具gcov的前端工具_LCOV_简介)