GCOV(1)

名称
gcov - カバレッジテストツール

書式
gcov [-v|--version] [-h|--help]
     [-b|--branch-probabilities] [-c|--branch-counts]
     [-n|--no-output] [-l|--long-file-names]
     [-f|--function-summaries]
     [-o|--object-directory directory] sourcefile

解説
gcov は、カバレッジテストを行うプログラムです。 GCC といっしょに用いると、あなたのプログラムを もっと効果的で高速に動くコードにするための解析ができます。 gcov をプロファイリングツールとして使うと、 プログラムを最適化するには どこを直すのが一番効果的かを見つけ出す事ができます。 また、 gprof とともに用いると、 コードのどの部分が実行時間をもっとも使っているのかを 調べる事ができます。

プロファイリングツールを使って、あなたのコードの性能を 解析することができます。 gcov や gprof のようなプロファイラを使うと、 性能にかかわる以下のような基礎的な統計情報が得られます。

•   コードの各行が何回実行されるか。

•   コードのどの部分が実際に実行されたのか。

•   コードの各部分の実行にどれだけの時間がかかっているか。

コンパイルされたコードがどのように動くのかがわかれば、 最適化すべきモジュールを見つけられます。 gcov を使えば、最適化のためにどこに力をいれればよいかを 決める事ができます。

ソフトウェア開発者は、 カバレッジテストをテストスイートといっしょに使う事で、 ソフトウェアがリリース可能な品質を持つことを確認できます。 テストスイートはプログラムが期待どおり動作する事を検証します。 一方、カバレッジテストによって、テストスイートがプログラム をどれだけテストしているかを調べる事ができます。 より良いテストとより良い最終製品を作るために、 テストスイートにどんな種類のテストケースを追加すればよいかを 決める事ができます。

gcov を使う場合には最適化無しでコンパイルするべきです。 なぜなら最適化によって数行のコードが 1 つにまとめられてしまうと、 実行時間の多くを消費している「ホットスポット」を探すのに 必要な情報が十分集まらなくなってしまうかもしれないからです。 さらに、 gcov は統計情報を行ごと (最小分析単位) に集めるので、 各行に文を 1 つずつ書くプログラミングスタイルにすると、 もっとも役に立つ結果が得られます。 ループや他の制御構文に展開される複雑なマクロを使うと、 マクロ呼び出しの 1 行にしか情報が出ませんから、 統計情報はあまり役に立たなくなってしまいます。 もしそのマクロが関数のように振る舞うものなら、 それをインライン関数に置き換えるとこの問題を解決できます。

gcov は sourcefile.gcov というログファイルを作ります。 これには sourcefile.c というソースファイルのどの行が 何回実行されたかが記録されています。 このログファイルを gprof といっしょに使えば、 あなたのプログラムの性能をファインチューニングする助けになります。 gprof からは、 gcov の出力といっしょに使える、 タイミング情報が得られます。

gcov は、 GCC でコンパイルされたコードのみで動作します。 他のプロファイルやテストカバレッジの仕組みとの互換はありません。

オプション

-h
--help
    gcov の使いかたを標準出力に表示して、 プログラムを終了します。 それ以外の処理はしません。

-v
--version
    gcov のバージョン番号を標準出力に表示して、 プログラムを終了します。 それ以外の処理はしません。

-b
--branch-probabilities
    分岐の回数を出力ファイルに書き出し、分岐のサマリを標準出力に表示します。 このオプションにより、プログラム中でそれぞれの分岐がどのくらい起きたかを 調べることができます。

-c
--branch-counts
    分岐が成立した割合 (パーセント) の代わりに、分岐の成立した回数を出力します。

-n
--no-output
    gcov 出力ファイルを作りません。

-l
--long-file-names
    インクルードされたソースファイルの名前として長いファイル名を使います。 たとえば、ヘッダファイル x.h がコードを含んでいて、 a.c によってインクルードされる場合、 gcov を a.c に対して実行すると、 出力ファイルは x.h.gcov ではなく、 a.c.x.h.gcov になります。 これは、 x.h が複数のファイルにインクルードされている場合に便利です。

-f
--function-summaries
    ファイルレベルのサマリの他に、各関数についてのサマリも出力します。

-o directory
--object-directory directory
    オブジェクトファイルのあるディレクトリを指定します。 gcov は、このディレクトリで .bb, .bbg, .da ファイルを探します。

gcov を使うには、最初にまず GCC の 2 つの特別なオプション、 -fprofile-arcs, -ftest-coverage を指定して、 プログラムをコンパイルしなければなりません。 これによってコンパイラは、 gcov が必要とする追加情報 (基本的にはプログラムのフローグラフ) を生成し、 また gcov が必要とするプロファイル情報を生成するコードを オブジェクトファイルに含めます。 これらの追加のファイルは、ソースコードのあるディレクトリに作られます。

プログラムを実行すると、プロファイル結果が生成されます。 -fprofile-arcs を指定してコンパイルしたソースファイル毎に、 対応する .da ファイルがソースディレクトリに作られます。

プログラムのソースファイル名を引数にして gcov を実行すると、 コードの各行に実行回数を示したソースリストを生成します。 プログラム名を tmp.c とすると、 gcov の基本機能は以下のようにして使います。

        $ gcc -fprofile-arcs -ftest-coverage tmp.c
        $ a.out
        $ gcov tmp.c
         87.50% of 8 source lines executed in file tmp.c
        Creating tmp.c.gcov.
gcov の出力は tmp.c.gcov に格納されています。 以下はそのサンプルです。

                        main()
                        {
                   1      int i, total;
                   1      total = 0;
                  11      for (i = 0; i < 10; i++)
                  10        total += i;
                   1      if (total != 45)
              ######        printf ("Failure\n");
                          else
                   1        printf ("Success\n");
                   1    }
-b オプションを使うと、出力は次のようになります。

        $ gcov -b tmp.c
         87.50% of 8 source lines executed in file tmp.c
         80.00% of 5 branches executed in file tmp.c
         80.00% of 5 branches taken at least once in file tmp.c
         50.00% of 2 calls executed in file tmp.c
        Creating tmp.c.gcov.
以下は、結果の tmp.c.gcov ファイルのサンプルです。

                        main()
                        {
                   1      int i, total;
                   1      total = 0;
                  11      for (i = 0; i < 10; i++)
        branch 0 taken = 91%
        branch 1 taken = 100%
        branch 2 taken = 100%
                  10        total += i;
                   1      if (total != 45)
        branch 0 taken = 100%
              ######        printf ("Failure\n");
        call 0 never executed
        branch 1 never executed
                          else
                   1        printf ("Success\n");
        call 0 returns = 100%
                   1    }
基本ブロック (basic block) について、 基本ブロックの最終行の次に、基本ブロックを終わらせた 分岐か関数呼び出しについての行を表示します。 ある行で終わる基本ブロックが複数ある場合、 そのソース行に対して複数の分岐や関数呼び出しが示される事があります。 この場合、それらの分岐や関数呼び出しには番号がふられます。 その番号とソース上の要素とのマッピングは単純ではありませんが、 もっとも小さい番号を持つ分岐や関数呼び出しが、 ソース上でもっとも左にあるのが普通です。

分岐 (branch) について、 一度でも実行された分岐は、 分岐の成立した回数を分岐の実行数で割った比率をパーセントで示します。 一度も実行されなかった分岐は ``never executed'' と表示します。

関数呼び出し (call) について、 一度でも実行された関数呼び出しは、 呼び出しから戻った回数を呼び出した回数で割った比率をパーセントで示します。 これは普通は 100% になりますが、 "exit" や "longjmp" を呼び出すために 戻ってこない事のある関数ではそれより少なくなるかもしれません。

実行回数は積算されます。 もし .da ファイルを消さずにプログラムを再実行すると、 ソースの各行の実行回数は、以前の結果に加えられます。 これにはいくつか役に立つ使い道を考えられます。 たとえばテストスイートの一部として行われる、 プログラムの複数回の実行結果をまとめたり、 長期間のより正確な情報を得るためにプログラムを非常に大きな回数実行して 結果をまとめたりする事ができます。

.da ファイルのデータは、プログラムの終了直前に保存されます。 -fprofile-arcs を指定してコンパイルされた各ファイルに 組み込まれているプロファイリングコードは、 まず始めに既存の .da ファイルを読み込みます。 もしその内容が実行プログラムと一致しなければ (基本ブロックの数が 合わなければ) 、ファイルの内容は無視します。 一致する場合には、 新しい実行回数を足し込んでから、データをファイルに書き出します。

  gcov と GCC の最適化の関係
あなたのコードを gcov を使って最適化しようとするならば、 最初にまず GCC の 2 つの 特別なオプション -fprofile-arcs, -ftest-coverage を指定して、 プログラムをコンパイルしなければなりません。 それに加えて GCC の他のどんなオプションも指定する事ができます。 一方、プログラム中の全ての行が実行される事を確認したい時には、 最適化を指定してはいけません。 一部のマシンでは最適化によって複数の行が 1 つにまとめられてしまい、 行の区別が無くなってしまう可能性があります。 たとえば以下のようなコードがあるとします:

        if (a != b)
          c = 1;
        else
          c = 0;
ある種のマシンではこのコードは 1 命令にコンパイルする事ができます。 その場合、各行に対応する命令コードが存在しないため、 gcov は行ごとの実行回数を数える事ができません。 したがってプログラムを最適化した時の gcov の出力は 以下のようになります。

              100  if (a != b)
              100    c = 1;
              100  else
              100    c = 0;
この出力は、最適化によって結合されたこのコードブロックが 100 回 実行された事を示しています。 4 行からなるブロックが 1 命令にまとめられたのですから、 これはある意味では正しいものです。 しかしながら、結果が 0 になった回数や 1 になった回数を、 この出力から読み取る事はできません。

関連項目
gpl(7), gfdl(7), fsf-funding(7), gcc(1) と gcc の Info エントリ

COPYRIGHT
Copyright (c) 1996, 1997, 1999, 2000, 2001 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being ``GNU General Public License'' and ``Funding Free Software'', the Front-Cover texts being (a) (see below), and with the Back-Cover Texts being (b) (see below). A copy of the license is included in the gfdl(7) man page.

(a) The FSF's Front-Cover Text is:

     A GNU Manual
(b) The FSF's Back-Cover Text is:

     You have freedom to copy and modify this GNU Manual, like GNU
     software.  Copies published by the Free Software Foundation raise
     funds for GNU development.