サイボウズ・ラボの光成です。
先日、社内で主にLinux上でC/C++を用いている開発者向けの講義をしました。 「こんなことができる」と知ってもらい、興味を持てば各自で勉強してもらおうと広く浅くツールを紹介しました。
gtags, ASan, Valgrind, addr2line, cppcheck, SystemTap, perfなどです。 興味があれば講義資料「C/C++プログラマのための開発ツール」をごらんください。
コンパイラオプション
受講者には新人やサイボウズ・ラボユースの学生もいたので基本的なところから紹介しました。
C/C++コンパイラを使うときはできるだけ警告オプションをつけるのが望ましいです。 警告が出るのは自分のコードの書き方に不備があることが多いからです。
gccやclangでは-Wall -Wextraは基本としてそれ以外にも有用なオプションがあります(C++用gccのオプション)。 一般にコンパイラによって出す警告は異なるので、可能なら複数のコンパイラでチェックした方がよいでしょう。
ソース読みの補助ツール
あるプロジェクトのコードを読むとき、関数名や変数名でひたすらgrepしている人がいます。 効率が悪いのであまり感心しません。
複数のディレクトリ内でまとめてgrep的なことをするにはag(The Silver Seacher)が高速で便利です。
また関数が定義されている場所や、呼び出されている場所を調べるにはGNU GLOBALを使うとよいです。自分が使っているエディタで使えるように設定しておきましょう。
クラス階層を視覚的に見たいときはDoxygenもよいでしょう。 関数の呼び出しグラフを可視化してくれるKcachegrindも便利です。
このように目的に応じて適切なツールを使うと効率よくコードを把握できます。
vimやemacsしか触ったことがないという人もたまには統合環境を使ってみるとよいでしょう。 何も設定しなくてもそういった機能を使えることが多いので、世界が広がるかもしれません。
デバッグ
gdbの最低限の使い方やcoreファイルを扱ったデモをしました。 それからlibSegFault.soをpreloadする方法、/proc/<プロセスid>/mapsやobjdump, addr2lineを使ってエラー箇所から関数を調べる方法などを紹介しました。
メモリ関係のチェックツールとしてAddressSanitizer(ASan), Valgrind, TCMallocなども紹介しました。 使い勝手とオーバーヘッドの少なさを考慮するとASanがよいと思います。
静的解析ツール
プログラムを実行せずにおかしなところを指摘してくれます。 コンパイラの警告の延長上にある機能です。
Visual Studioの/analyzeオプションやフリーソフトのcppcheck, clang付属でXcodeの静的解析ツールとしても使われているscan-buildなどがあります。 それぞれ得意、不得意があるのでできれば複数のツールで調べるとよいでしょう。
たとえばうっかり書いてしまいそうな次のコードがあります。 どこがおかしいか分かりますか?
int f(int a) { if (a != 3 || a != 5) return 4; return 2; }
このコードに対してVisual Studioは
不適切な演算子です: || を使用した相互排除は常に 0 でない定数となります。 && を使用しようとしましたか?
と警告してくれます。面白いですね。
静的解析ツールにはCoverityといった優れた商用ツールもあります。
SystemTap
Linux kernelの中身を動的に調べられるツールです。 awk/Cに似たスクリプトを書いて実行すると、裏でkernelモジュールに変換されて動きます。
特定のネットワーク処理やdisk IO処理がkernelのどこでどのように実行されているかを調べられます。
ユーザコードのstacktraceなども表示でき、ltraceやstraceみたいな使い方もできます。 kernel内部で使われている構造体のメンバ変数を表示できるなど非常に強力なツールです。
SystemTap/Examplesにはたくさんのサンプルスクリプトが掲載されているので最初はそれらをコピーして使うだけでも有用でしょう。
今回は紹介しませんでしたが「半年かかったバグ調査の顛末は」ではblktraceが活躍したり, 「ファイルキャッシュクリアの謎」ではFtraceを使ったりしました。
perf
CPUが持つ詳細な情報を用いてサンプリング形式でプロファイルするツールです。
kernelシンボルを入れておけばperf topで今システムのどこが重たいのかをリアルタイムで見ながら探せます。 システム開発中に、たまにperf topして、予想していない関数が上位に来ていると原因を調べて性能改善できたことが何度かあります。
図はわざと無限ループするPythonスクリプトを実行したときに上位に来た関数のうち、PyDict_GetItemの内部に入ったところです。 逆アセンブルされて、左側のCPU負荷が高いところを示す数値は常時変わっています。 初めて見るとなかなか感動すると思います。
まとめ
以上、駆け足で紹介しました。もちろん今回の資料で紹介してなくて有用なツールもたくさんあります。 また新しいツールもどんどんでてくるでしょう。 アンテナを張って、自分の中で常時情報を更新できるようにしておきたいものです。