Oracle Solaris Studio 12.2 Discover および Uncover ユーザーズガイド

第 3 章 コードカバレッジツール (Uncover)

Uncover を使用するための要件

Uncover は、Solaris 10 5/08 オペレーティング システム、またはそれ以降の Solaris 10 update を実行している SPARC ベースまたは x86 ベースのシステム上の少なくとも -O1 最適化オプションを使用した、Sun Studio 12 Update 1、Oracle Solaris Studio Express 6/10、Oracle Solaris Studio 12.2 コンパイラ、または GCC for Sun Systems 4.2.0 以降のコンパイラを使用してコンパイルされたバイナリ上で機能します。

上記のようにコンパイルされるバイナリには、Uncover がカバレージデータの収集用に計測するためにバイナリを確実に逆アセンブリする情報が含まれています。

-g オプションを使用して、バイナリのコンパイル時にデバッグ情報を生成することにより、Uncover はソースコードレベルのカバレージ情報を使用できます。バイナリが -g オプションを使用してコンパイルされない場合、プログラムカウンタ (PC) ベースのカバレージ情報のみを使用します。

Uncover の使用法

    Uncover を使用してカバレージ情報を生成するには、3 ステップのプロセスがあります。

  1. バイナリの計測

  2. 計測済みバイナリの実行

  3. カバレージレポートの生成と表示

バイナリの計測

入力バイナリは、実行可能ファイルまたは共有ライブラリとすることができます。分析したいバイナリの計測は個別に行う必要があります。

uncover コマンドを使用してバイナリを計測します。たとえば、次のコマンドは、バイナリ a.out を計測し、入力 a.out を計測済み a.out で上書きします。また、このコマンドは、接尾辞 .uc を持つディレクトリ (この場合は a.out.uc) を作成します。この中に、カバレージデータが収集されます。入力バイナリのコピーはこのディレクトリに保存されます。


uncover a.out

-d directory カバレージデータディレクトリを directory に作成するよう Uncover に指示することができます。このオプションは、複数のバイナリ用のカバレージデータを収集する場合に役立ち、カバレージデータディレクトリのすべてが同じディレクトリ内に作成されるようにします。また、異なる場所から同じ計測済みバイナリの異なるインスタンスを実行する場合、このオプションを使用すると、これらの実行のすべてから取得されるカバレージデータが同じカバレージデータディレクトリに確実に蓄積されるようになります。

-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 コマンドオプションを使用すると、レポートを HTML 形式で生成して Web ブラウザで表示したり、ASCII 形式で生成して端末ウィンドウで表示したりすることができます。

-e on | off

カバレージレポートのための実験ディレクトリを生成し、パフォーマンスアナライザ GUI で実験を表示します。デフォルトではオンになっています。

-H html_directory

カバレージデータを指定のディレクトリに HTML 形式で保存し、それを Web ブラウザで自動的に表示します。デフォルトでオフになっています。

-h または -?

ヘルプ。

-n

カバレージレポートを生成しますが、パフォーマンスアナライザや Web ブラウザなどのビューアを起動しません。

-t ascii_file

指定されたファイルで ASCII カバレージレポートを生成します。デフォルトでオフになっています。

-V

Uncover バージョンを出力して終了します。

-v

冗長。Uncover が実行する内容のログを出力します。

出力形式は 1 つだけ有効になるため、複数の出力オプションを指定する場合、Discover はコマンドの最後のオプションを使用します。


uncover a.out

このコマンドは、バイナリ a.out を計測し、入力 a.out を上書きして、現作業ディレクトリに a.out.uc カバレージデータディレクトリを作成し、a.out.uc ディレクトリに入力 a.out のコピーを保存します。a.out がすでに計測されている場合、警告メッセージが表示され、計測は実行されません。


uncover -d coverage a.out

このコマンドは、a.out.uc カバレージディレクトリをディレクトリ coverage に作成する点を除いて、最初の例が行うすべてのことを実行します。


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 %)」カウンタを一覧表示した列が表示されます。列ヘッダーをクリックすると、どの列でもデータのソートキーとして指定できます。列ヘッダーの矢印をクリックすると、ソート順が逆になります。

パフォーマンスアナライザの Uncover レポートの「関数 (Functions)」タブ

「カバレージ外 (Uncoverage)」カウンタ

「カバレージ外 (Uncoverage)」メトリックは、Uncover の非常に強力な機能です。この列を降順のソートキーとして使用する場合、最上部に表示される関数は、カバレージを増やす可能性が最も高い関数です。例では、main() 関数が「カバレージ外 (Uncoverage)」列で最大数を持つため、リストの最上部に表示されます。(sigprof() および sigprofh() 関数は同数を持つため、アルファベット順に一覧表示されます。)

main() 関数のカバレージ外の数は、関数が呼び出される原因となるスイートにテストが追加される場合に潜在的にカバーされる可能性のあるコードのバイト数です。カバレージが実際に増加する量は、関数の構造によって異なります。関数に分岐がなく、呼び出すすべての関数が直線関数でもある場合、カバレージは実際には定められたバイト数により増加します。ただし、一般的に、カバレージの増加は潜在的に想定されるよりおそらくずっと少ないです。

「カバレージ外 (Uncoverage)」列の 0 以外の値を持つカバーされていない関数は、カバーされていないルート関数と呼ばれ、カバーされている関数によってすべて呼び出されることを意味します。カバーされていない非ルート関数によってのみ呼び出される関数は、独自のカバレージ外の数を持ちません。テストスイートは、潜在性の高いカバーされていない関数をカバーするように改良されるにつれて、これらの関数は、後続の実行で、カバーされるか、またはカバーされないことが明らかにされると想定されます。

カバレージ数は排他的ではありません。

「関数カウント (Function Count)」カウンタ

関数カウントは関数が呼び出された回数ですが、カバレージ分析のコンテキストでは、実際の数は重要ではありません。重要なことは数が 0 か 0 以外であるかということです。数が 0 の場合、関数はカバーされません。数が 0 以外の場合、関数はカバーされます。関数の命令が実行される場合、関数はカバーされるとみなされます。

この列で、トップレベル以外のカバーされていない関数を検出できます。ある関数の関数カウントが 0 で、カバレージ外の数も 0 である場合、関数はトップレベルのカバーされている関数ではありません。

「命令の実行 (Instr Exec)」カウンタ

「命令の実行 (Instr Exec)」カウンタには、動的な命令カウントが表示されます。「関数 (Functions)」タブに、関数ごとに実行される命令の総数が表示されます。このカウンタは、「ソース (Source)」タブ (「「ソース」タブ」を参照) および「逆アセンブリ (Disassembly) タブ (「「逆アセンブリ」タブ」を参照) にも表示されます。

「カバーされているブロックの割合 (%) (Block Covered %)」カウンタ

関数ごとに、「カバーされているブロックの割合 (%) (Block Covered %)」カウンタに、カバーされている関数の基本的なブロックの割合が表示されます。この数により、関数がいかに適切にカバーされているかがわかります。<Total> 行のこの数は無視してください。これは列のパーセンテージの合計であり、意味がありません。

「カバーされている命令の割合 (%) (Instr Covered %)」カウンタ

関数ごとに、「カバーされている命令の割合 (%) (Instr Covered %)」カウンタに、カバーされている関数の命令の割合が表示されます。この数によっても、関数がいかに適切にカバーされているかがわかります。<Total> 行のこの数は無視してください。これは列のパーセンテージの合計であり、意味がありません。

「ソース」タブ

バイナリを -g オプションを使用してコンパイルした場合、「ソース (Souece)」タブにはプログラムのソースコードが表示されます。Uncover はバイナリレベルでプログラムを計測し、最適化してプログラムをコンパイルしているため、このタブのカバレージ情報は解釈するのが困難な可能性があります。

「ソース (Source)」タブの「命令の実行 (Instr Exec)」カウンタには、各ソース行に対して実行される命令の総数が表示され、これは基本的に文レベルのコードカバレージ情報です。0 以外の値は、文がカバーされていることを意味します。0 の値は、文がカバーされていないことを意味します。変数宣言およびコメントには命令の実行カウントがありません。

パフォーマンスアナライザの Uncover レポートの「ソース (Source)」タブ

「逆アセンブリ」タブ

「ソース (Source)」タブのある行を選択し、次に「逆アセンブリ (Disassembly)」タブを選択する場合、アナライザは、バイナリで選択した行を検出し、その逆アセンブリを表示しようとします。

このタブの「命令の実行 (Instr Exec)」カウンタには、各命令が実行される回数が表示されます。

パフォーマンスアナライザの Uncover レポートの「逆アセンブリ (Disassembly)」タブ

「命令頻度」タブ

「命令頻度 (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 は機械命令のカバレージを検出し、このカバレージをソースコードと関連付けます。一部のソースコード文は関連した機械命令を持たないため、Uncover はそのような文のカバレージを報告しないと思われる場合があります。たとえば、次のコードフラグメントを考えみましょう:

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

Uncover が if 文の 0 以外の実行数を報告することを期待しても、コンパイラはこのコードを削除する可能性があるため、Uncover は計測中にそれを表示しません。そのため、これらの命令に対してカバレージは報告されません。