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不相配致使的,由於二者之間都有個時間戳用來記錄是否是相同的。

相關文章
相關標籤/搜索