GCOV 使用用例

 

 

 

1.GCOV查看arm-linux代码覆盖率php

1、           关于gcov工具css

gcov伴随gcc 发布。gcc编译加入-fprofile-arcs -ftest-coverage 参数生成二进制程序,执行测试用例生成代码覆盖率信息。
一、如何使用gcovhtml

用GCC编译的时候加上-fprofile-arcs -ftest-coverage选项,连接的时候也加上。
fprofile-arcs参数使gcc建立一个程序的流图,以后找到适合图的生成树。只有不在生成树中的弧被操纵(instrumented):gcc添加了代码来清点这些弧执行的次数。当这段弧是一个块的惟一出口或入口时,操纵工具代码(instrumentation code)将会添加到块中,不然建立一个基础块来包含操纵工具代码。前端

gcov主要使用.gcno和.gcda两个文件。
.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。
.gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其余的概要信息(而gcda只能在程序运行完毕后才能产生的)。
Gcov执行函数覆盖、语句覆盖和分支覆盖。linux

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

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

而这时候的main.c.gcov,和tmp.c.gcov就包含了函数和代码执行次数的信息,咱们能够查看结果:
      -:   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.

2、关于lcov

Lcov则是上的gcov 结果展示的一个前端,能够将覆盖率信息转换成html展示。

1. 如何访问用户空间应用程序代码覆盖数据的示例
---------------------------------------------------------------------
前提条件:使用 GCC 以 -fprofile-arcs 和-ftest-coverage 选项编译程序。假设编译目录名称为"/root/test/code_cover/",而后执行:

以个人一个实例/root/test/code_cover/下的fork.c为例看代码的覆盖率:

首先进入/root/test/code_cover/目录

a) 重置计数器

   lcov --directory . --zerocounters

b) 收集当前代码覆盖状态到一个文件(应用程序启动和中止至少一次后,该命令才能正常工做)

   lcov --directory . --capture --output-file app.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

c) 获取 HTML 输出

   genhtml -o results app.info

其中的“-o results”是指示结果存放在什么位置的。

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%)

使用 web 浏览器打开 index.html 文件查看代码覆盖结果。

 

 

 

 

3、Linux内核覆盖率测试:

将最终的 gcov 内核模块文件复制到 system wide modules 目录或者 PERL 脚本所在目录。以 root 身份, 执行:

Gcov:在对Linux内核程序进行代码覆盖率测试时,一样能够采用gcov,可是须要对kernel打一个补丁。Gcov的内核补丁下载地址:http://ltp.sourceforge.net/coverage/gcov.php。下载gcov内核补丁(wget http://downloads.sourceforge.net/ltp/gcov-kernel-2.tar.gz),解压补丁,而后为一个kernel打补丁(patch –p1 < /home/linux-v3.4-mem/gcov-kernel-2/linux-2.6.18-gcov.patch)注意打补丁时应该处于内核的主目录下也即/home/linux-v3.4-mem,打完补丁以后,经过make menuconfig配置gcov,配置页面显示以下:

 

 

 

配置完毕以后,从新编译内核,将编译成功的gcov这个内核模块/home/linux-v3.4-mem /kernel/gcov/gcov-proc.ko拷贝到网络文件系统下面,arm linux系统启动后加载这个模块

(1)/insmod gcov-proc.ko

而后再跑其余测试程序,跑了一段时间,你会发如今/proc/gcov目录下有各类gcov的统计文件:

/proc/gcov # ls

arch      crypto    init      kernel    security  vmlinux

block     drivers   ipc       net       sound

把这整个目录拷贝到fedora虚拟机下的一个目录,我是拷贝到/nfs/kernel_test/gcov目录下,而后

(2)收集当前代码覆盖状态到一个文件

  lcov --directory . --output-file kernel.info

(3) 获取 HTML 输出

  genhtml kernel.info

使用 web 浏览器打开 index.html 文件查看代码覆盖结果。

 

 

 

 

 

上面是怎样获取内核运行代码覆盖率的通常方法及流程。

但若是咱们只想获取一个程序运行时的内核代码覆盖率,改怎么办呢???

这里先说几个gcov-proc模块的特性:

(1)模块属性:

咱们发现/sys/module/gcov_proc下有parameters文件夹,进去咱们发现有两个属性文件:

/sys/module/gcov_proc/parameters # ls

gcov_link     gcov_persist

这两个属性是控制什么的呢???看看官方表述:

- gcov_link=0/1 (default is 1): When set to non-zero, symbolic links to

    source and gcov graph files are created in /proc/gcov along with the data

    files.

  - gcov_persist=0/1 (default is 0): When set to non-zero, gcov data for

    kernel modules is kept even after those modules are unloaded so that

    coverage measurements can be extended to module cleanup code. To clear

this persistent data, write to /proc/vmlinux.

(2)重启内核覆盖率采集的数据

To reset coverage data for a specific file, simply write to the associated data

file in the /proc/gcov hierarchy:

 

    echo 0 > /proc/gcov/kernel/signal.da

 

To reset all coverage data, write to the extra file '/proc/gcov/vmlinux':

 

echo 0 > /proc/gcov/vmlinux

 

4、获取程序运行时段的内核覆盖率

个人方法是在运行应用程序(这里面是以个人/nfs/memtest/timetest下的timetest应用程序为例)的开始先用“echo 0 > /proc/gcov/vmlinux”指令将咱们的/proc/gcov下的统计信息所有清空让它从新计数的,下面说下咱们的方法和步骤:

一、  先得到一个含义gcov信息的内核和gcov-proc.ko,这个上面已经说过了;

二、  启动linux内核,而后安装gcov-proc.ko

/memtest # insmod gcov-proc.ko

gcov-proc: initializing proc module: persist=0 link=1 format=gcc 3.4

gcov-proc: init done

/memtest # cd timetest/

/memtest/timetest # ls

20100106.log   fp2            timetest       timetest.c     timetest.gcno

20100111.log   results        timetest-lcov  timetest.gcda

三、  这时先用“echo 0 > /proc/gcov/vmlinux”指令清空gcov,而后运行timetest,而后将

/proc/gcov拷贝到/tmp下面,这是防止直接拷到虚拟机下会产生大量的网络函数调用,增长统计偏差。

/memtest/timetest # echo 0 > /proc/gcov/vmlinux && ./timetest && cp -r /proc/gcov/ /tmp

game over count1 is 0xc9413e40,count2 is 0x0,count3 is 0x3c8b1e45,count4 is 0x0

/memtest/timetest # ls /tmp

gcov

四、  如今统计的数据是放在/tp/gcov下面的,咱们须要将之拷贝到上位机的虚拟机中才能分析,由于咱们的lcov只能在虚拟机中才能运行的。

/memtest/timetest # cp -r /tmp/gcov/ ./

/memtest/timetest #

五、  如今须要转到虚拟机下接着运行lcov来产生最后的html页面了。

[root@localhost timetest]# cd gcov/

[root@localhost gcov]# lcov --directory . --capture --output-file timetest.info

[root@localhost gcov]# genhtml -o results timetest.info

这样就生成了最后基本上只运行在timetest时间段的内核代码覆盖率了。

 

 

 

 

2.gcov使用实例

1.         使用说明 

使用GCOV进行代码覆盖率统计,须要注意:

1)            在编译时不要加优化选项,由于加编译选项后,代码会发生变化,这样就找不到哪些是本身写的热点代码。

2)            若是代码中使用复杂的宏,好比说这个宏展开后是循环或者其余控制结构, gcov只在宏调用出现的那一行报告 ,若是复杂的宏看起来像函数,能够用内联函数来代替。

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

4)            能够用gcov,lcov测试linux内核覆盖率,参考

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

这里只讨论应用程序的覆盖率。

2.         使用实例

使用主要有三个步骤:

1)            编译阶段:加入编译选项gcc –o hello –fprofile-arcs –ftest-coverage hello,生成记录程序流程图等信息

 

2)            数据收集与提取阶段:./hello.,生成具体的运行信息

这一阶段生成的数据信息自动保存到。o文件所在的目录,也就是说若是存在/usr/build/hello.o,则生成/usr/build/hello.gcda,可是若是前边目录不存在就会出错。

3)            生成数据报告: gcov  hello.c

 

如下给出gcov针对c++项目nmap的应用过程

Nmap是一个强大的端口扫描程序,同时Nmap也是著名安全工具Nessus所依赖工具。代码行数在3万行以上。

执行:

  1. CXXFLAGS=”-fprofile-arcs -ftest-coverage” LIBS=-lgcov ./configure  èmakefile
  2. Make     è 每一个源文件产生一个.gcno文件
  3. ./nmap   è每一个源文件生成一个.gcda文件
  4. Gcov *cc  è每一个源文件生成一个.gcov文件

    

步骤一:检测代码

按照nmap项目readme文档编译运行一遍,保证代码正确性

步骤二:增长使用gcov的编译选项:-fprofile-arcs -ftest-coverage,连接选项-lgcov或者-coverage

对于手动写的Makefile代码,直接增长编译选项便可

对一些自动生成的Makefile文件,运行./configure –h 查看增长Makefile编译链接选项的方法,增长编译选项:-fprofile-arcs -ftest-coverage ,经过一些环境变量设置便可,好比本程序设置为 CXXFLAGS=”-fprofile-arcs -ftest-coverage” LIBS=-lgcov ./configure

 

步骤三:编译链接

修改Makefile文件后,执行make, 针对每一个源文件会生成.gcno文件

 

步骤四:测试

运行单个测试用例或测试用例组,生成.gcda文件,以下运行./nmap 127.0.0.1后,结果以下

 

步骤五:运行gcov生成覆盖测试信息

以下所示,分析其中的一个源文件及其相关联文件的测试覆盖率状况,默认状况下会生成sourefilename.c.gcov文件,能够添加-l,-p选项生成具体的目录及长文件名。以下所示,分别对main.cc与output.cc的进行覆盖率统计。这里查看的是行覆盖率,也能够添加-b,-f给出分支覆盖率信息,具体能够经过man gcov查看

下边是给出的生成行覆盖率的信息:

main.cc

 

Output.cc

 

步骤六:查看.gcov文件

显示源代码的执行状况,以下所示,查看output.cc的执行状况,如下分别是output.cc.gcov文件的头与部分信息,其中红框部分标注该行代码的执行次数,-表示没有被插桩到的代码行。

 

 

下图是分支覆盖率信息:

 

函数开始前给出总体信息:

一些分支状况:

 

步骤七: 用lcov查看总体代码覆盖状况

使用lcov前对覆盖率数据清空,lcov –z –d ./

在源码路径下运行lcov –b ./  -d ./  -c -o output.info,-b指示以当前目录做为相对路径,-d表示统计目录中的覆盖数据文件而不是内核数据,并将生成的信息存于-o所示文件,具体参数参考:lcov –h 查看

 

      最后,能够合并多个覆盖率信息,用-a 选项

      Lcov  –add-tracefile .out/a.info –a ./out.info –a ./out/b.info

步骤八:用genhtml查看整体视图与网页视图

以下,能够看出本次覆盖测试成功instrument的行数有近两万行,执行的行数却只有三千多行,能够反复的增长测试用例,提升覆盖测试率。下图分别给出了总体覆盖率和各个源文件的覆盖状况。

 

 

 

 

3.         常见错误

1.        .gcda文件目录出错,找不到要建立的目录,这种主要用于跨平台状况。

这个是因为.gcda文件的生成默认保存到.o所在的目录,可是若是.o所在目录不存在,就会出现错误。

设置环境变量能够解决这个问题。

设置GCOV_PREFIX=/target/run’同GCOV_PREFIX_STRIP=1

则生成的.gcda文件 将会保存到 /target/run/build/foo.gcda。

2.        the gcov message “Merge mismatch for summaries”

能够将.gcda所有删除或者对整个文件所有编译,而不是单个改变的文件,这个是因为gcda与gcno不相配致使的,由于二者之间都有个时间戳用来记录是否是相同的。

相关文章
相关标签/搜索