http://practical-scheme.net/wiliki/wiliki.cgi?Shiro (2009/04/13)
面白いです。 shiro さんが書かれたものの亜種になるものも多いですが、少し私も書いてみようかと。スレッドやらイベントは下記とかぶる。
http://d.hatena.ne.jp/shinichiro_h/20081001#1222794259
多スレッド
少ないうちはいいんですが、多いとバグに関係があるスレッドを探すだけでかなり大変。 race condition 時は「明らかな症状が出る時点では既に痕跡が消えているケース」の亜種になるかなと。
あとタスクキューみたいなのがからむと次の問題とかぶる。
イベントモデル
シングルスレッドで select をぶん回してる時なんかに、返事来たらこの callback 実行してねーと asynchronous な実行をしたりするわけですが (JS の XMLHttpRequest もそうですね)、 callback でヘンなことが起きても、何故ヘンな callback が登録されたか、誰がその callback が登録したか、なんかが stack 巻き戻っちゃってるのでわからん、という。
これも「明らかな症状が出る時点では既に痕跡が消えているケース」と言って良いんじゃないかなぁと。
多プロセス
スレッドよりさらにキツい。「外部コンポーネントが関わるケース」の亜種かなぁと。スレッドで出る問題も出る。
プロセスが多くなってきて、ネットワークごしにあちこちで動いたりされるとそもそも全プロセスにアタッチするのが現実的じゃなくなる。
MapReduce とかまさにそんな感じだと思うんだけど、 unittest をやるのは当然として、入力データをそこらじゅうでチェックしまくって、想定外のデータが来たら入力データに関する情報を可能な限りたくさん撒き散らかして落とす、っていうのが一番良いかなぁと思う。 glog の CHECK みたいなのが大活躍。
同じところを何度も通る系
基本的に、一つのパスを一回しか通らないソフトはデバッグしやすいと思う。そのパスに break point しかければいいから。 kernel なんかは比較的そんな感じなんじゃないかなぁと推測する。 file system とかはそうもいかんでしょうけど。
同じところを何度も通って、特定の条件の時だけ妙なことが起きるケースでは、条件つき break を仕込むんだと思う。でも shiro さんも書いておられるけど、条件つき break ってイマイチ使えないことが多いんだよな。
Window manager
一風変わって、 WM は割と gdb 難しめだった。開発に使っているのと別の X server で走らせると切り替えに時間がかかるのが欝陶しいし、同じ X server でやると break 中とかは開発に支障が多少出るし…というような。
http://practical-scheme.net/wiliki/wiliki.cgi?Shiro (2009/04/13) の下の方を受けて
単純に私がアホなだけですが、リモートログインできないマシンでフルスクリーンで動くゲームを gdb つきで起動して落ちたりすると、もう電源切る以外にはどうしようもなくなるというドジっこ話が。大学の MacOSX でゲームの Mac への移植とかやってた時にたまにあった…
ゴルフ
バイナリゴルフとかしてると、読ませただけで gdb が落ちるバイナリとかになってて、どうしようもない。つっても printf も動かんので、 core を手動で読んだりしてた。
個人的には
printf を擁護したくなる理由として、ログをたくさん吐いておくとか、フラグかなんかでたくさん吐けるようにしておくことは、とても良いことだと思っている、ということがあると思う。
確かにデバッガ様があれば複雑な構造体の中身とか読めるのだけど、それは単なるダンプであって、作った人間がこのフィールドの情報は重要である、と考えて出力するログ情報にはどうしても劣るんだよな。でまぁ同時にそいうログ出力コードっていうのは、ソースを理解する際にも結構役に立ったりすると思う。
まぁ printf デバッグというよりかはログ吐けって話だけど。
printf が使いものにならないケース
ぱっと思い当たるのは既に動いちゃってておかしな動きをしているサーバとか。あとビルドに時間がかかるのもそうだけど、プロセスの初期化に時間がかかるソフトもきつい。そういう時は gdb 大活躍。
あと嬉しいのは printf しにくい複雑なデータ構造に toString 的なのが準備されてない場合とかですかね。 dumper とか作ったのはそれがモチベーションだったわけだけど。