◆GCOVカーネル
Linux にはカバレッジ計測する gcov コマンドというものがあります。
しかし、一般的な gcov でカバレッジ計測が可能なのはユーザー空間のプログラムです。
(厳密には gcov コマンド自体は、
カバレッジ計測用のコンパイルオプションでコンパイルされたプログラムの
実行結果を収集、可視化するためのものですが。)
Linux カーネルはユーザー空間のプログラムではないので、
一般的な gcov コマンド等ではカバレッジ計測できないのですが、
それを行なってしまうのがGCOVカーネルなのです。
元々は LTP (Linux Test Project) のサイトからGCOVカーネル用のパッチをダウンロードして適用する必要があったのですが、いつのまにか本家の Linux に取り込み済みのようです。
# 3.18 以降なら ARM にも対応しています。
# (3.17 以前でも本質的には対応されてます。 Kconfig メニュー上表示されませんが。)
◆カーネルカバレッジデータのサンプル
どんな感じのデータが取得できるのかは、まずは見てもらった方が早いと思います。
下記は自分が raspberry pi でGCOVカーネル(3.19.3) を実際に動かして取得したデータです。
GCOVカーネルカバレッジデータの出力サンプル
arch/arm/lib/uaccess_with_memcpy.c の __copy_to_user_memcpy() の部分を
↓下記に抽出しました。
if 文などの分岐単位でカバレッジ計測されます。
左にその行の実行回数が表示されています。

◆GCOVカーネルのビルド
では実際のGCOVカーネルのビルド方法です。
"make menuconfig" により、
CONFIG_GCOV_KERNEL と CONFIG_GCOV_PROFILE_ALL を有効にし、
Linux カーネルをビルドします。(Linux カーネルのビルド方法詳細はここを参照)
参考までに、本家 LTP の説明ページ。
http://ltp.sourceforge.net/coverage/gcov.php
(実際動かしてみると、結構重くなってましたので、あくまでプロファイリング用のカーネルと割り切りましょう。)
◆lcov コマンドのインストール
GCOVカーネルで取得したカバレッジデータを
上記サンプルのように html 化して出力してくれる lcov というツール(?)があります。
ホスト環境に lcov コマンドをインストールしておきます。
(Linux カーネルをクロスビルドしているホスト側です。構築方法詳細はここを参照)
または、下記でもいいです。
いつもの apt-get でもインストールされたんですが、
バージョンが最新(1.11)ではなく1.10でしたので、
上記のどちらかを推奨します。
◆カーネルカバレッジデータの取得
GCOVカーネルをビルドしたなら、そのカーネルでRaspberry Pi を実際に動かしてみます。
/sys/kernel/debug/gcov/ 以下にカバレッジデータが蓄積されていますので、
そのデータを取得し、ホスト環境に持って行きます。
◆カーネルカバレッジデータのhtml化
ところ変わって、こちらはホスト環境側になります。
KERNEL_DIR はクロスビルドした Linux カーネルのディレクトリです。
クロス環境での lcov の使い方がいまいちよく分からなかったので、
この辺りは自分がトライ&エラーで試した結果になります。
なのでもっとスマートな方法があるかもしれないです。
カバレッジデータとソースコードを同ディレクトリに置くために、取得データをカーネルツリーにコピーします。
(lcov のオプションで別ディレクトリのままでもいけそうな気もするのですが。)
クロス用の gcov を指定し、lcovコマンドを叩きます。output-file、output-directory の名前は何でもいいです。
out ディレクトリ下の index.html をブラウザで開いてください。
参考までに、本家 LTP の説明ページ。あっさりし過ぎ。。。
http://ltp.sourceforge.net/coverage/lcov.php
Linux にはカバレッジ計測する gcov コマンドというものがあります。
しかし、一般的な gcov でカバレッジ計測が可能なのはユーザー空間のプログラムです。
(厳密には gcov コマンド自体は、
カバレッジ計測用のコンパイルオプションでコンパイルされたプログラムの
実行結果を収集、可視化するためのものですが。)
Linux カーネルはユーザー空間のプログラムではないので、
一般的な gcov コマンド等ではカバレッジ計測できないのですが、
それを行なってしまうのがGCOVカーネルなのです。
元々は LTP (Linux Test Project) のサイトからGCOVカーネル用のパッチをダウンロードして適用する必要があったのですが、いつのまにか本家の Linux に取り込み済みのようです。
# 3.18 以降なら ARM にも対応しています。
# (3.17 以前でも本質的には対応されてます。 Kconfig メニュー上表示されませんが。)
◆カーネルカバレッジデータのサンプル
どんな感じのデータが取得できるのかは、まずは見てもらった方が早いと思います。
下記は自分が raspberry pi でGCOVカーネル(3.19.3) を実際に動かして取得したデータです。
GCOVカーネルカバレッジデータの出力サンプル
arch/arm/lib/uaccess_with_memcpy.c の __copy_to_user_memcpy() の部分を
↓下記に抽出しました。
if 文などの分岐単位でカバレッジ計測されます。
左にその行の実行回数が表示されています。

◆GCOVカーネルのビルド
では実際のGCOVカーネルのビルド方法です。
"make menuconfig" により、
CONFIG_GCOV_KERNEL と CONFIG_GCOV_PROFILE_ALL を有効にし、
Linux カーネルをビルドします。(Linux カーネルのビルド方法詳細はここを参照)
General setup ---># CONFIG_GCOV_KERNEL のメニューは CONFIG_DEBUG_FS を有効にしないと表示されません。
GCOV-based kernel profiling --->
[*] Enable gcov-based kernel profiling
[*] Profile entire Kernel
Specify GCOV format (Autodetect) --->
参考までに、本家 LTP の説明ページ。
http://ltp.sourceforge.net/coverage/gcov.php
(実際動かしてみると、結構重くなってましたので、あくまでプロファイリング用のカーネルと割り切りましょう。)
◆lcov コマンドのインストール
GCOVカーネルで取得したカバレッジデータを
上記サンプルのように html 化して出力してくれる lcov というツール(?)があります。
ホスト環境に lcov コマンドをインストールしておきます。
(Linux カーネルをクロスビルドしているホスト側です。構築方法詳細はここを参照)
$ git clone https://github.com/linux-test-project/lcov.gitで、lcov 1.11 がインストールできると思います。
$ cd lcov/
$ sudo make install
または、下記でもいいです。
$ curl -L -O http://downloads.sourceforge.net/ltp/lcov-1.11.tar.gz
$ tar xvzf lcov-1.11.tar.gz
$ cd lcov-1.11/
$ sudo make install
いつもの apt-get でもインストールされたんですが、
バージョンが最新(1.11)ではなく1.10でしたので、
上記のどちらかを推奨します。
$ sudo apt-get install lcov
◆カーネルカバレッジデータの取得
GCOVカーネルをビルドしたなら、そのカーネルでRaspberry Pi を実際に動かしてみます。
/sys/kernel/debug/gcov/ 以下にカバレッジデータが蓄積されていますので、
そのデータを取得し、ホスト環境に持って行きます。
$ sudo mount -t debugfs nodev /sys/kernel/debug/※ピンク色の部分はクロスビルドした環境によって異なります。
$ sudo cp -a /sys/kernel/debug/gcov/home/mint/raspi/linux-3.19.y ./gcov-data
$ sudo tar cvjf gcov.tar.bz2 gcov-data/
◆カーネルカバレッジデータのhtml化
ところ変わって、こちらはホスト環境側になります。
KERNEL_DIR はクロスビルドした Linux カーネルのディレクトリです。
$ export KERNEL_DIR=/home/mint/raspi/linux-3.19.yRaspberry Pi 上で取得した gcov.tar.bz2 を適当なディレクトリに展開します。
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ mkdir gcov-tmp/
$ cd gcov-tmp/
$ tar xvjf gcov.tar.bz2
クロス環境での lcov の使い方がいまいちよく分からなかったので、
この辺りは自分がトライ&エラーで試した結果になります。
なのでもっとスマートな方法があるかもしれないです。
カバレッジデータとソースコードを同ディレクトリに置くために、取得データをカーネルツリーにコピーします。
(lcov のオプションで別ディレクトリのままでもいけそうな気もするのですが。)
$ cp -a gcov-data/* ${KERNEL_DIR}/
クロス用の gcov を指定し、lcovコマンドを叩きます。output-file、output-directory の名前は何でもいいです。
$ lcov --capture --directory ${KERNEL_DIR}/ --output-file coverage.info --gcov-tool ${CROSS_COMPILE}gcovgenhtml により out ディレクトリ下に html が生成されますので、
$ genhtml coverage.info --output-directory out
out ディレクトリ下の index.html をブラウザで開いてください。
参考までに、本家 LTP の説明ページ。あっさりし過ぎ。。。
http://ltp.sourceforge.net/coverage/lcov.php