コード網羅ツールは、コードのどの部分が実際に実行され、どの部分が一回も呼ばれなかったかを、プログラマが判断できるようにする。GHCには計器付きコードを生成するオプションがあり、生成されたコードはHaskell Program Coverage(HPC)ツールキット(GHCに付属している)の一員としてコード網羅率を記録する。このコード網羅率情報は、HPCツールを使って人間が理解できる形式に変換することができる。
正しい計器付きコードは二種類の網羅率情報を供給する。ソース網羅率と真偽値制御網羅率である。ソース網羅率は、プログラムがどれくらい隅々まで使われたかの度合いで、三つの水準、すなわち宣言(最上位のものと局所的なものの両方)、分岐(複数の等式やcaseの枝からの選択)、式(あらゆる深さのもの)で測られる。真偽値網羅率は、構文的に真偽値が要求される全ての場所(ガード、条件、qualifier(訳者: qualifierって何?))について、どれくらいTrueとFalseの両方が得られたかである。
HPCは、この両方の種類の情報を、二つの主要な方法で表示する。一つは、統計要約の付いたテキスト形式の報告書(hpc報告)であり、もう一つはソースの色付きマークアップ(hpcマークアップ)である。真偽値網羅については、それぞれのガード、条件、qualifierについて、四つの結果があり得る。TrueとFalseの両方が起こった、Trueだけ、Falseだけ、一回も評価されなかった、である。hpcマークアップの出力において、黄色の背景による強調はプログラムのその部分が一回も評価されなかったことを示し、緑の背景は常にTrueだったことを、赤い背景は常にFalseだったことを示す。
例として、Recip.hsという、逆数の正確な十進表現を計算するプログラムを使おう。小数の循環部分は括弧に入れて示すことにする。
reciprocal :: Int -> (String, Int) reciprocal n | n > 1 = ('0' : '.' : digits, recur) | otherwise = error "attempting to compute reciprocal of number <= 1" where (digits, recur) = divide n 1 [] divide :: Int -> Int -> [Int] -> (String, Int) divide n c cs | c `elem` cs = ([], position c cs) | r == 0 = (show q, 0) | r /= 0 = (show q ++ digits, recur) where (q, r) = (c*10) `quotRem` n (digits, recur) = divide n r (c:cs) position :: Int -> [Int] -> Int position n (x:xs) | n==x = 1 | otherwise = 1 + position n xs showRecip :: Int -> String showRecip n = "1/" ++ show n ++ " = " ++ if r==0 then d else take p d ++ "(" ++ drop p d ++ ")" where p = length d - r (d, r) = reciprocal n main = do number <- readLn putStrLn (showRecip number) main
HPCの計器付与は-fhpcフラグで有効になる。
$ ghc -fhpc Recip.hs --make
HPC index(.mix)ファイルはサブディレクトリ.hpcに置かれる。これはHPCにとっての.hiファイルのようなものだと考えられる。
$ ./Recip 1/3 = 0.(3)
以下のようにして、網羅率のテキスト要約を生成できる。
$ hpc report Recip 80% expressions used (81/101) 12% boolean coverage (1/8) 14% guards (1/7), 3 always True, 1 always False, 2 unevaluated 0% 'if' conditions (0/1), 1 always False 100% qualifiers (0/0) 55% alternatives used (5/9) 100% local declarations used (9/9) 100% top-level declarations used (5/5)
マークアップされたソースを生成することもできる。
$ hpc markup Recip writing Recip.hs.html
これによって、Haskellモジュール一つにつき一つのファイルと、四つのインデックスファイル(hpc_index.html、hpc_index_alt.html、hpc_index_exp.html、hpc_index_fun.html)が生成される。
網羅率を有効にするのは簡単で、-fhpcフラグを使えばよい。計器付きのものと計器付きでないものは自由に混ぜて構わない。Mainモジュールをコンパイルするとき、hpcコンパイルされたモジュールがあれば、GHCが自動的にそれを検出して、正しい初期化コードを追加する。
hpcツールキットはcvs/svn/darcs的なインタフェースを持っている。つまり、一つのバイナリに沢山の機能単位が含まれている。
$ hpc Usage: hpc COMMAND ... Commands: help Display help for hpc or a single command Reporting Coverage: report Output textual report about program coverage markup Markup Haskell source with program coverage Processing Coverage files: sum Sum multiple .tix files in a single .tix file combine Combine two .tix files in a single .tix file map Map a function over a single .tix file Coverage Overlays: overlay Generate a .tix file from an overlay file draft Generate draft overlay that provides 100% coverage Others: show Show .tix file in readable, verbose format version Display version for hpc
一般的に言って、これらのオプションは、計器付きバイナリが生成した後の.tixファイルに対して動作する。hpcは、生の.tixファイルと、生成される詳細な報告書の間の仲介として働く。
hpcツールは、アプリケーションをビルドした場所の最上位ディレクトリに居て、その同じ最上位ディレクトリに.tixファイルがあることを前提とする。別のディレクトリに対してhpcを使うには--srcdirフラグを使うことができる。また、複数の場所でコンパイルされたプログラム(パッケージでは普通のことである)を分析する場合は、--srcdirを複数回使えばよい。
ここからは、hpcのメジャーモードについて詳しく説明する。
hpc reportは、網羅率のテキスト形式の報告書を与える。デフォルトで、includeやexcludeが使われない限り、報告書を生成する上ですべてのモジュールとパッケージが考慮に入る。--per-moduleフラグが使われない限り、報告書は要約である。--xml-outputオプションは、hpcを使って網羅率を収集するツールのためにある。
$ hpc help report Usage: hpc report [OPTION] .. <TIX_FILE> [<MODULE> [<MODULE> ..]] Options: --per-module show module level detail --decl-list show unused decls --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR sub-directory that contains .mix files default .hpc [rarely used] --xml-output show output in XML
hpc markupはソースファイルをマークアップして色付きhtmlにする。
$ hpc help markup Usage: hpc markup [OPTION] .. <TIX_FILE> [<MODULE> [<MODULE> ..]] Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR sub-directory that contains .mix files default .hpc [rarely used] --fun-entry-count show top-level function entry counts --highlight-covered highlight covered code, rather that code gaps --destdir=DIR path to write output to
hpc sumは任意の個数の.tixファイルを足し合わせて、単一の.tixファイルにする。hpc sumは元の.tixファイルを変更せず、新しい.tixファイルを作る。
$ hpc help sum Usage: hpc sum [OPTION] .. <TIX_FILE> [<TIX_FILE> [<TIX_FILE> ..]] Sum multiple .tix files in a single .tix file Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --output=FILE output FILE --union use the union of the module namespace (default is intersection)
hpc combineはhpcのスイスアーミーナイフである。.tixファイルの差(difference)をとること、ある.tixファイルから別の.tixファイルを引く(subtract)こと、二つの.tixファイルを足す(add)ことができる。hpc combineは元の.tixファイルを変更せず、新しい.tixファイルを生成する。
$ hpc help combine Usage: hpc combine [OPTION] .. <TIX_FILE> <TIX_FILE> Combine two .tix files in a single .tix file Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --output=FILE output FILE --function=FUNCTION combine .tix files with join function, default = ADD FUNCTION = ADD | DIFF | SUB --union use the union of the module namespace (default is intersection)
hpc mapは.tixファイルを反転(invert)したり零化(zero)したりする。hpc mapは元の.tixファイルを変更せず、新しい.tixファイルを生成する。
$ hpc help map Usage: hpc map [OPTION] .. <TIX_FILE> Map a function over a single .tix file Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --output=FILE output FILE --function=FUNCTION apply function to .tix files, default = ID FUNCTION = ID | INV | ZERO --union use the union of the module namespace (default is intersection)
overlayはHPCの実験的機能で、網羅率のテキスト記述である。hpc draftは.tixファイルからdraft overlayを作るのに使われ、hpc overlayはoverlayから.tixファイルを生成する。
% hpc help overlay Usage: hpc overlay [OPTION] .. <OVERLAY_FILE> [<OVERLAY_FILE> [...]] Options: --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR sub-directory that contains .mix files default .hpc [rarely used] --output=FILE output FILE % hpc help draft Usage: hpc draft [OPTION] .. <TIX_FILE> Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR sub-directory that contains .mix files default .hpc [rarely used] --output=FILE output FILE
HPCは.tixファイルをロックしようとしないので、同じディレクトリでバイナリを並行に実行すると競合条件が現れるだろう。バイナリの名前を変更する以外に、生成される.tixファイルの名前を変えるすべはない。HPCはGHCiでは動作しない。