Oracle Solaris Studio 12.2 Discover 和 Uncover 用户指南

第 3 章 代码覆盖率工具 (Uncover)

Uncover 的使用要求

Uncover 使用通过 Sun Studio 12 Update 1、Oracle Solaris Studio Express 6/10 或 Oracle Solaris Studio 12.2 编译器编译的二进制文件,或通过 GCC for Sun Systems 4.2.0 或更高版本编译器(至少使用 -O1 优化选项)的二进制文件(在基于 SPARC 或 x86 的系统上,且运行的是 Solaris 10 5/08 操作系统或更高的 Solaris 10 Update 版本)。

按照说明进行编译的二进制文件包含一些信息,Uncover 可使用这些信息可靠地反汇编二进制文件,以便对其进行校验以收集覆盖率数据,

在编译二进制文件时使用 -g 选项生成调试信息,可以让 Uncover 使用源代码级别的覆盖率信息。如果二进制文件不是使用 -g 选项编译的,Uncover 只能使用基于程序计数器 (program counter, PC) 的覆盖率信息。

使用 Uncover

    使用 Uncover 生成覆盖率信息的过程分为三个步骤:

  1. 校验二进制文件

  2. 运行校验过的二进制文件

  3. 生成并查看覆盖率报告

校验二进制文件

输入的二进制文件可以是可执行文件或共享库。必须分别校验每个要分析的二进制文件。

使用 uncover 命令校验二进制文件。例如,以下命令将校验二进制文件 a.out,并使用校验过的 a.out 来覆写输入的 a.out。该命令还将创建一个后缀为 .uc 的目录(本例中为 a.out.uc),将在该目录中收集覆盖率数据。输入二进制文件的副本保存在此目录中。


uncover a.out

可以使用 -d directory 选项让 Uncover 在 directory 中创建覆盖率数据目录。当您为多个二进制文件收集覆盖率数据时,此选项十分有用,使您可以在同一个目录中创建所有的覆盖率数据目录。此外,如果从不同的位置运行同一个校验过的二进制文件的不同实例,使用此选项可确保在同一个覆盖率数据目录中累积所有这些运行中的覆盖率数据。

如果不使用 -d 选项,将在当前运行目录中创建覆盖率数据目录。

如果对某个已校验的输入二进制文件运行 uncover 命令,Uncover 将发出错误消息,通知您该二进制文件已经校验,无法再次校验,您可以运行该二进制文件来生成覆盖率数据。

运行校验过的二进制文件

校验二进制文件后,您可以按正常方式运行它。每次运行校验过的二进制文件时,都会在 Uncover 执行校验期间创建的、后缀为 .uc 的覆盖率数据目录中收集代码覆盖率数据。由于 Uncover 数据收集是多线程安全的,并且是多进程安全的,因此,对进程中的并发运行或线程的数量没有限制。覆盖率数据将累积所有的运行和线程。

生成并查看覆盖率报告

要生成覆盖率报告,请对覆盖率数据目录运行 uncover 命令。例如:


uncover a.out.uc

此命令将根据 a.out.uc 目录中的覆盖率数据生成一个名为 binary_name.er 的 Oracle Solaris Studio 性能分析器实验目录,启动性能分析器 GUI,并显示该实验。如果当前目录或主目录中存在 .er.rc 文件(请参见《Oracle Solaris Studio 12.2 性能分析器》手册,分析器显示实验的方式可能会受影响。

还可以使用 uncover 命令选项生成可以在 Web 浏览器中查看的 HTML 报告,或者生成可以在终端窗口中查看的 ASCII 报告:

-e on | off

生成覆盖率报告的实验目录,并在性能分析器 GUI 中显示实验。缺省情况下为打开。

-H html_directory

在指定的目录中以 HTML 格式保存覆盖率数据,并在 Web 浏览器中自动显示这些数据。缺省情况下为关闭。

-h-?

帮助。

-n

生成覆盖率报告,但不启动性能分析器或 Web 浏览器等查看器。

-t ascii_file

在指定的文件中生成 ASCII 覆盖率报告。缺省情况下为关闭。

-V

输出 Uncover 版本信息并退出。

-v

详细。输出 Uncover 正在执行的操作的日志。

仅启用了一种输出格式,因此,如果指定了多个输出选项,Discover 仅使用命令中的最后一个选项。

示例


uncover a.out

此命令将校验二进制文件 a.out,覆写输入的 a.out,在当前目录中创建 a.out.uc 覆盖率数据目录,并在 a.out.uc 目录中保存输入 a.out 的副本。如果已校验 a.out,将显示警告消息,并且不执行校验。


uncover -d coverage a.out

此命令将执行第一个示例中执行的所有操作,不过,它会在目录 coverage 中创建 a.out.uc 覆盖率目录。


uncover a.out.uc

此命令使用 a.out.uc 覆盖率目录中的数据在工作目录中创建代码覆盖率实验 (a.out.er),并启动性能分析器 GUI 以显示该实验。


uncover -H a.out.html a.out.uc

此命令使用 a.out.uc 覆盖率目录中的数据在 a.out.html 目录中创建 HTML 代码覆盖率报告,并在 Web 浏览器中显示该报告。


uncover -t a.out.txt a.out.uc

此命令使用 a.out.uc 覆盖率目录中的数据在 a.out.txt 文件中创建 ASCII 代码覆盖率报告。

了解性能分析器中的覆盖率报告

缺省情况下,在对覆盖率目录运行 uncover 命令时,会在 Oracle Solaris Studio 性能分析器中以实验的形式打开覆盖率报告。分析器使用 "Functions"(函数)、"Source"(源代码)、"Disassembly"(反汇编)和 "Inst-Freq"(指令频率)选项卡来显示覆盖率数据。

"Functions"(函数)选项卡

在分析器中打开覆盖率报告时,"Functions"(函数)选项卡处于选中状态。该选项卡显示了一些列,其中列出了每个函数的 "Uncoverage"(未覆盖率)、"Function Count"(函数计数)、"Instr Exec"(指令执行)、"Block Covered %"(块覆盖率)和 "Instr Covered %"(指令覆盖率)计数器。单击任何一列的标题可以将该列设置为数据的排序键。单击列标题上的箭头可以反转排序顺序。

性能分析器的 Uncover 报告的 "Functions"(函数)选项卡

"Uncoverage"(未覆盖率)计数器

"Uncoverage"(未覆盖率)度量是一项极其强大的 Uncover 功能。如果使用此列作为排序键,降序排列时,显示在最上面的函数是最有可能提高覆盖率的函数。在本例中,main() 函数位于列表的顶端,因为它在 "Uncoverage"(未覆盖率)列中的数目最多。(sigprof()sigprofh() 函数的数目相同,因此它们按字母顺序排列。)

main() 函数的未覆盖率数目是指,向导致调用该函数的套件添加一个测试时可能覆盖的代码的字节数。根据函数的结构,覆盖率实际增加的量会有所不同。如果该函数没有分支,并且它调用的所有函数也是直线型函数,则覆盖率确实只会增加指定的字节数。但一般而言,覆盖率增长会小于潜在值,也许会小很多。

"Uncoverage"(未覆盖率)列中使用非零值的未覆盖函数称为根未覆盖函数,表示它们都由覆盖函数调用。仅由非根未覆盖函数调用的函数没有自己的未覆盖率数目。假定在后续的运行中,随着测试套件的改善而覆盖了潜力较大的未覆盖函数,这些函数将被覆盖,或者揭开以成为未覆盖函数。

覆盖率数目是非排他性的。

"Function Count"(函数计数)计数器

函数计数是某个函数被调用的次数,但在覆盖率分析上下文中,实际计数无关紧要。关键在于计数是零还是非零。如果计数为零,表示该函数未覆盖。如果计数非零,表示该函数已覆盖。如果执行了函数中的任一指令,该函数将视为已覆盖。

可以检测到此列中的非顶层未覆盖函数。如果某个函数的函数计数是零,并且未覆盖率数目也是零,表示该函数不是顶层覆盖函数。

"Instr Exec"(指令执行)计数器

"Instr Exec"(指令执行)计数器显示动态指令计数。"Functions"(函数)选项卡中显示了为每个函数执行的指令总数。此计数器还出现在 "Source"(源代码)选项卡(请参见"Source"(源代码)选项卡)和 "Disassembly"(反汇编)选项卡(请参见"Disassembly"(反汇编)选项卡)中。

"Block Covered %"(块覆盖率)计数器

对于每个函数,"Block Covered %"(块覆盖率)计数器显示该函数中被覆盖的基本块的百分比。通过此数目可以大致了解函数的覆盖情况。请忽略 <Total> 行中的这个数字,它是列中的百分比之和,没有意义。

"Instr Covered %"(指令覆盖率)计数器

对于每个函数,"Instr Covered %"(指令覆盖率)计数器显示该函数中被覆盖的指令的百分比。通过此数目也可以大致了解函数覆盖的情况。请忽略 <Total> 行中的这个数字,它是列中百分比之和,没有意义。

"Source"(源代码)选项卡

如果二进制文件是使用 -g 选项编译的,"Source"(源代码)选项卡将显示程序的源代码。由于 Uncover 在二进制文件级别上校验您的程序,并且已使用优化设置编译程序,因此,此选项卡中的覆盖率信息很难解释。

"Source"(源代码)选项卡中的 "Instr Exec"(指令执行)计数器显示了为每个源代码行执行的指令数,它本质上是语句级别的代码覆盖率信息。非零值表示该语句已覆盖;零值表示该语句未覆盖。变量声明和注释没有指令执行计数。

性能分析器的 Uncover 报告的 "Source"(源代码)选项卡

"Disassembly"(反汇编)选项卡

如果在 "Source"(源代码)选项卡中选择一行,然后选择 "Disassembly"(反汇编)选项卡,分析器将在二进制文件中查找选定的行,并显示其反汇编。

此选项卡中的 "Instr Exec"(指令执行)计数器显示了每个指令的执行次数。

性能分析器的 Uncover 报告的 "Disassembly"(反汇编)选项卡

"Inst-Freq"(指令频率)选项卡

"Inst-Freq"(指令频率)选项卡显示总的覆盖率摘要。

性能分析器的 Uncover 报告的 "Inst-Freq"(指令频率)选项卡

了解 ASCII 覆盖率报告

如果从覆盖率数据目录中生成覆盖率报告时指定了 -t 选项,Uncover 会将覆盖率报告写入指定的 ASCII 文件(文本文件)。


UNCOVER Code Coverage
Total Functions: 95
Covered Functions: 58
Function Coverage: 61.1%
Total Basic Blocks: 568
Covered Basic Blocks: 258
Basic Block Coverage: 45.4%
Total Basic Block Executions: 564,812,760
Average Executions per Basic Block: 994,388.66
Total Instructions: 6,201
Covered Instructions: 3,006
Instruction Coverage: 48.5%
Total Instruction Executions: 4,760,934,518
Average Executions per Instruction: 767,768.83
Number of times this program was executed: unavailable
Functions sorted by metric: Exclusive Uncoverage 

Excl.       Excl.     Excl.      Excl.       Name
Uncoverage  Function  Block      Instr
            Count     Covered %  Covered %
13404       6004876   5464       5384        <Total>
 1036             0      0          0        main
  980             0      0          0        iofile
  748             0      0          0        do_vforkexec
  732             0      0          0        callso
  708             0      0          0        do_forkexec
  648             0      0          0        callsx
  644             0      0          0        sigprof
  644             0      0          0        sigprofh
  556             0      0          0        do_chdir
  548             0      0          0        correlate
  492             0      0          0        do_popen
  404             0      0          0        pagethrash
  384             0      0          0        so_cputime
  384             0      0          0        sx_cputime
  348             0      0          0        itimer_realprof
  336             0      0          0        ldso
  304             0      0          0        hrv
  300             0      0          0        do_system
  300             0      0          0        do_burncpu
  300             0      0          0        sx_burncpu
  288             0      0          0        forkcopy
  276             0      0          0        masksignals 
  256             0      0          0        sigprof_handler
  256             0      0          0        sigprof_sigaction
  216             0      0          0        do_exec
  196             0      0          0        iotest
  176             0      0          0        closeso
  156             0      0          0        gethrustime
  144             0      0          0        forkchild
  144             0      0          0        gethrpxtime 
  136             0      0          0        whrlog
  112             0      0          0        masksig
   92             0      0          0        closesx
   84             0      0          0        reapchildren
   36             0      0          0        reapchild
   32             0      0          0        doabort
    8             0      0          0        csig_handler
    0             1     66         72        acct_init
    0             1    100        100        bounce 
    0            63    100         96        bounce_a
    0            60    100        100        bounce-b
    0            16     71         58        check_sigmask
    0             1     83         77        commandline
    0             1    100         98        cputime
    0             1    100         98        dousleep
    0             1    100        100        endcases
    0             1    100         95        ext_inline_code
    0             1    100         96        ext_macro_code
    0             1    100         99        fitos
    0             2     81         80        get_clock_rate
    0             1    100        100        get_ncpus
    0             1    100        100        gpf
    0             1    100        100        gpf_a
    0             1    100        100        gpf_b
    0            10    100         93        gpf_work
    0             1    100         97        icputime
    0             1    100         96        inc_body
    0             1    100         96        inc_brace
    0             1    100         95        inc_entry
    0             1    100         95        inc_exit
    0             1    100         96        inc_func
    0             1    100         94        inc_middle
    0             1     57         72        init_micro_acct
    0             1     50         43        initcksig
    0             1    100         95        inline_code
    0             1    100         95        macro_code
    0             1    100         98        muldiv
    0       6000000    100        100        my_irand
    0             1    100         98        naptime
    0            19     50         83        prdelta
    0            21    100        100        prhrdelta
    0            21    100        100        prhrvdelta
    0             1    100        100        prtime
    0           552    100         98        real_recurse
    0             1    100        100        recurse
    0             1    100        100        recursedeep
    0             1    100         95        s_inline_code
    0             1    100        100        sigtime
    0             1    100         95        sigtime_handler
    0            19    100        100        snaptod
    0             1    100        100        so_init
    0             2     66         75        stpwtch_alloc
    0             1    100        100        stpwtch_calibrate
    0             2     75         66        stpwtch_print
    0          2002    100        100        stpwtch_start  
    0          2000     90         91        stpwtch_stop
    0             1    100        100        sx_init
    0             1    100         99        systime
    0             3    100         95        tailcall_a 
    0             3    100         95        tailcall_b
    0             3    100         95        tailcall_c
    0             1    100        100        tailcallopt
    0             1    100         97        underflow
    0            21     75         71        whrvlog
    0            19    100        100        wlog

Instruction frequency data from experiment a.out.er

Instruction frequencies of /export/home1/synprog/a.out.uc
Instruction               Executed     ()
 TOTAL                  4760934518 (100.0)
 float ops              2383657378 ( 50.1)
 float ld st            1149983523 ( 24.2)
 load store             1542440573 ( 32.4)
 load                    882693735 ( 18.5)
 store                   659746838 ( 13.9)
-------------------------------------------
Instruction               Executed     ()      Annulled   In Delay Slot
 TOTAL                  4760934518 (100.0)           
 add                     713013787 ( 15.0)           16         1501335
 subcc                   558774858 ( 11.7)            0            6002
 br                      558769261 ( 11.7)            0               0 
 stf                     432500661 (  9.1)          726        36299281
 ldf                     408226488 (  8.6)           40       103000396
 faddd                   391230847 (  8.2)            0               0
 fdtos                   366200726 (  7.7)            0               0
 fstod                   360200000 (  7.6)            0               0 
 lddf                    288250336 (  6.1)          500       282200229
 stw                     138028738 (  2.9)        26002        25974065
 lduw                    118004305 (  2.5)           71        94000270
 ldx                      68212446 (  1.4)            0            2000
 stx                      68211370 (  1.4)            7        23532716
 fitod                    36026002 (  0.8)            0               0
 sethi                    36002986 (  0.8)            0             228 
 fdtoi                    30000001 (  0.6)            0               0
 fdivd                    26000088 (  0.5)            0               0
 call                     22250348 (  0.5)            0               0
 srl                      21505246 (  0 5)            0              21
 stdf                     21006038 (  0.4)            0               0
 or                       19464766 (  0.4)            0        10981277 
 fmuls                     6004907 (  0.3)            0               0
 jmpl                      6004853 (  0.1)            0               0
 save                      6004852 (  0.1)            0               0
 restore                   6002294 (  0.1)            0         6004852
 sub                       6000019 (  0.1)            0               0
 xor                       6000000 (  0.1)            0               0
 fitos                     6000000 (  0.1)            0               0
 fstoi                     6000000 (  0.1)            0               0
 and                       6000000 (  0.1)            0               0
 andn                      6000000 (  0.1)            0               0
 sll                       3505225 (  0.1)            0               0 
 nop                       3505219 (  0.1)            0         3505219
 fxtod                        7763 (  0.0)            0               0      
 bpr                          6000 (  0.0)            0               0
 fcmped                       4837 (  0.0)            0               0
 fbr                          4837 (  0.0)            0               0
 fmuld                        2850 (  0.0)            0               0
 orcc                          383 (  0.0)            0               0
 sra                           241 (  0.0)            0               0
 ldsb                          160 (  0.0)            0               0
 mulx                           87 (  0.0)            0               0
 stb                            31 (  0.0)            0               0
 mov                            21 (  0.0)            0               0
 fdtox                          15 (  0.0)            0               0
==========================================================

了解 HTML 覆盖率报告

HTML 报告类似于性能分析器中显示的报告。

HTML 覆盖率报告

如果单击某个函数的函数名称链接或 trimmed 链接,将显示该函数的反汇编数据。

反汇编显示画面

如果单击某个函数的 Caller-callee 链接,将显示调用方-被调用方数据。

调用方-被调用方显示画面

使用 Uncover 时的限制

只能校验有注释的代码

Uncover 只能校验根据Uncover 的使用要求中的说明准备的代码。无注释代码可能来自链接到二进制文件中的汇编语言代码,或者来自使用早于该部分中所列版本的编译器或操作系统编译的模块。

在准备时,特别要排除包含 asm 语句或 .il 模板的汇编语言模块和函数。

计算机指令可能不同于源代码

Uncover 处理计算机代码。它会查找计算机指令的覆盖率,然后将此覆盖率与源代码相关联。某些源代码语句没有关联的计算机指令,因此,看上去好像是 Uncover 没有报告这些语句的覆盖率。例如,请看以下代码片段:

#define A 100
#define B 200
...
   if (A>B) {
        ...
   }

根据您的预期,Uncover 应该对 if 语句报告非零执行计数,但编译器很可能会删除此代码,使得 Uncover 在校验期间看不到它。因此,不会针对这些指令报告覆盖率数据。