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 命令校验二进制文件。例如,以下命令将校验二进制文件 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 报告:
生成覆盖率报告的实验目录,并在性能分析器 GUI 中显示实验。缺省情况下为打开。
在指定的目录中以 HTML 格式保存覆盖率数据,并在 Web 浏览器中自动显示这些数据。缺省情况下为关闭。
帮助。
生成覆盖率报告,但不启动性能分析器或 Web 浏览器等查看器。
在指定的文件中生成 ASCII 覆盖率报告。缺省情况下为关闭。
输出 Uncover 版本信息并退出。
详细。输出 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"(函数)选项卡处于选中状态。该选项卡显示了一些列,其中列出了每个函数的 "Uncoverage"(未覆盖率)、"Function Count"(函数计数)、"Instr Exec"(指令执行)、"Block Covered %"(块覆盖率)和 "Instr Covered %"(指令覆盖率)计数器。单击任何一列的标题可以将该列设置为数据的排序键。单击列标题上的箭头可以反转排序顺序。
"Uncoverage"(未覆盖率)度量是一项极其强大的 Uncover 功能。如果使用此列作为排序键,降序排列时,显示在最上面的函数是最有可能提高覆盖率的函数。在本例中,main() 函数位于列表的顶端,因为它在 "Uncoverage"(未覆盖率)列中的数目最多。(sigprof() 和 sigprofh() 函数的数目相同,因此它们按字母顺序排列。)
main() 函数的未覆盖率数目是指,向导致调用该函数的套件添加一个测试时可能覆盖的代码的字节数。根据函数的结构,覆盖率实际增加的量会有所不同。如果该函数没有分支,并且它调用的所有函数也是直线型函数,则覆盖率确实只会增加指定的字节数。但一般而言,覆盖率增长会小于潜在值,也许会小很多。
"Uncoverage"(未覆盖率)列中使用非零值的未覆盖函数称为根未覆盖函数,表示它们都由覆盖函数调用。仅由非根未覆盖函数调用的函数没有自己的未覆盖率数目。假定在后续的运行中,随着测试套件的改善而覆盖了潜力较大的未覆盖函数,这些函数将被覆盖,或者揭开以成为未覆盖函数。
覆盖率数目是非排他性的。
函数计数是某个函数被调用的次数,但在覆盖率分析上下文中,实际计数无关紧要。关键在于计数是零还是非零。如果计数为零,表示该函数未覆盖。如果计数非零,表示该函数已覆盖。如果执行了函数中的任一指令,该函数将视为已覆盖。
可以检测到此列中的非顶层未覆盖函数。如果某个函数的函数计数是零,并且未覆盖率数目也是零,表示该函数不是顶层覆盖函数。
"Instr Exec"(指令执行)计数器显示动态指令计数。"Functions"(函数)选项卡中显示了为每个函数执行的指令总数。此计数器还出现在 "Source"(源代码)选项卡(请参见"Source"(源代码)选项卡)和 "Disassembly"(反汇编)选项卡(请参见"Disassembly"(反汇编)选项卡)中。
对于每个函数,"Block Covered %"(块覆盖率)计数器显示该函数中被覆盖的基本块的百分比。通过此数目可以大致了解函数的覆盖情况。请忽略 <Total> 行中的这个数字,它是列中的百分比之和,没有意义。
对于每个函数,"Instr Covered %"(指令覆盖率)计数器显示该函数中被覆盖的指令的百分比。通过此数目也可以大致了解函数覆盖的情况。请忽略 <Total> 行中的这个数字,它是列中百分比之和,没有意义。
如果二进制文件是使用 -g 选项编译的,"Source"(源代码)选项卡将显示程序的源代码。由于 Uncover 在二进制文件级别上校验您的程序,并且已使用优化设置编译程序,因此,此选项卡中的覆盖率信息很难解释。
"Source"(源代码)选项卡中的 "Instr Exec"(指令执行)计数器显示了为每个源代码行执行的指令数,它本质上是语句级别的代码覆盖率信息。非零值表示该语句已覆盖;零值表示该语句未覆盖。变量声明和注释没有指令执行计数。
如果在 "Source"(源代码)选项卡中选择一行,然后选择 "Disassembly"(反汇编)选项卡,分析器将在二进制文件中查找选定的行,并显示其反汇编。
此选项卡中的 "Instr Exec"(指令执行)计数器显示了每个指令的执行次数。
"Inst-Freq"(指令频率)选项卡显示总的覆盖率摘要。
如果从覆盖率数据目录中生成覆盖率报告时指定了 -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 报告类似于性能分析器中显示的报告。
如果单击某个函数的函数名称链接或 trimmed 链接,将显示该函数的反汇编数据。
如果单击某个函数的 Caller-callee 链接,将显示调用方-被调用方数据。
Uncover 只能校验根据Uncover 的使用要求中的说明准备的代码。无注释代码可能来自链接到二进制文件中的汇编语言代码,或者来自使用早于该部分中所列版本的编译器或操作系统编译的模块。
在准备时,特别要排除包含 asm 语句或 .il 模板的汇编语言模块和函数。
Uncover 处理计算机代码。它会查找计算机指令的覆盖率,然后将此覆盖率与源代码相关联。某些源代码语句没有关联的计算机指令,因此,看上去好像是 Uncover 没有报告这些语句的覆盖率。例如,请看以下代码片段:
#define A 100 #define B 200 ... if (A>B) { ... }
根据您的预期,Uncover 应该对 if 语句报告非零执行计数,但编译器很可能会删除此代码,使得 Uncover 在校验期间看不到它。因此,不会针对这些指令报告覆盖率数据。