http://my.oschina.net/alphajay/blog/33725
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的視圖
(3.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的使用方法,基本原理,一些實際中可能會遇到的問題以及解決思路。
- 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
http://blog.csdn.net/jinzhuojun/article/details/7802872
原文地址:http://blog.csdn.net/ariesjzj/article/details/7802872
1. Cygwin在/bin下有兩種編譯器可選:i686-pc-mingw32-gcc和i686-pc-cygwin-gcc。默認為前者。Cygwin編譯出來的可執行文件能很好地使用gcov和lcov。但如果項目本身是Mingw的,雖然可將用Mingw的gcc完成編譯,但不能用gcov,即便用-fprofile-arcs -ftest-coverage編譯和用-lgcov鏈接,運行時出錯。而在Windows上用純Mingw環境編譯出來的卻可以用。
2. 注意在編譯時源文件的路徑最好用相對路徑,否則會在生成的gcno文件中加入MinGW的Windows目錄前綴,有時會讓code coverage report的生成過程失敗。
3. 還有個問題就是Mingw沒有自帶lcov,不過好在lcov就是一個perl腳本,比較容易移植。把Linux上的lcov(包含五個文件lcov, gendesc, genhtml, geninfo, genpng)復制到Windows的Cygwin的bin目錄即可。
4. 如果lcov處理時hang住,只需在geninfo中刪除
push(@gcov_options, “-a”) if ($gcov_caps->{‘all-blocks’});
一行。
When gcc 4.1 (using gcov) next line:
p = new Class;
is reported as 100% branch coverage <-- THIS IS OK for me.
Why using gcc 4.4 and higher same line is reportted as:
[+ -] p = new Class; (50% branch coverage)... <-- THIS IS a problem for covering 100% !!!
Can I set any extra options to newer gcc versions in order to report same branch coverage as gcc 4.1 for single lines as "p = new Class;".
Thanks in advance.
We have some C/C++ files with and without exceptions handling, so lcov/gcov process "exceptions handling" for each code block.
Inside a normal block, for example:
int main(void)
{
...
...
[+ -] printf("Hello\n");
...
}
gcov reports that printf line has a "branch coverage" of 50% ---> WHY ?
Because exceptions handling is enabled !!!
In order to solve this issue, specify:
-fno-exceptions
in g++ command line.
Example:
g++ -O0 --coverage -fno-exceptions -fno-inline ....
Thanks !