新人技術者のためのロジカル・シンキング入門(1) ―― いかにしてバグの原因を突き止めるか
【4】自分のブロックが原因かどうかを判定(2/2)
● リアルタイム性にかかわる部分は切り分けがやっかい
かりに,入力データでは単体モジュールがハングアップしなかったとします.その場合,この先の切り分けがめんどうです.なぜなら通常,単体モジュールを確認するときは組み込みOS上でリアルタイムに動かせません.そのため,動作確認の際に単体モジュールではハングアップが起きなくても,リアルタイム処理特有の問題(例えば割り込み耐力の有無,処理速度が限界を超えていないかなど)を洗い出せないからです(図10).ひょっとすると,割り込み動作を実行しているときにのみ発生するハードウェアのバグにひっかかっているのかもしれません.あるいはもっと単純なケースで,OSに実装したときのメモリ配置と単体モジュールをテストするメモリ配置が異なっていて,単体では現象が隠れているだけかもしれません.
図10 リアルタイムでの単体テスト
ファイル入出力を用いたテストで問題なく動作したら,次にリアルタイムで動作する単体テストを試みる.リアルタイムでのみ発現するようなエラーは,実は切り分けが困難.「割り込み耐力がない」,「処理速度が間に合わない」,「ハードウェアのバグにつかまった」など,さまざまな要因が考えられる.一つ一つ切り分けるしかない.
このようなときはどうするかというと,考えられる問題をできる限り多く挙げ,順序良く確認を進めるしかありません.メモリ配置が違うのであれば,システムとそろえて単体テストをやり直すことも必要になります.問題の入力データだと実は不正アドレスにアクセスしていて,それが単体だと気づかないなどという場合には,このケースが多いと思われるので注意が必要です.処理速度がオーバしたかどうかは単体テストでも確認できるでしょう.
リアルタイム処理特有のハードウェアのバグにひっかかっていると疑われる場合,コンパイル・オプションを変えるとか,コンパイラの版数を落とす(または上げる)といったことで現象が変わることもあるので,試してみるとよいかもしれません.アセンブリ・コードをC言語に置き換えたらハングアップしなくなる,ということもありえるからです(図11).
図11 一部の関数に対してアセンブリ言語による最適化がなされていた場合
最初は高級言語(多くの場合はC言語)で実装してアセンブリ言語に変えるのが常とう手段.したがって,処理速度が間に合うのなら,元の高級言語による実装に戻してみて確認する.
● ロジカルに「自分が原因ではない」ことを導き出す
最後に,システムにおける切り分けで重要な目安となるのは,「自分のブロックが原因かどうか」を判定するということです.要するに,自分の担当ブロックのせいなのかそうでないのかを客観的な証拠に基づいて切り分けていくということです.
これは,前述した「私が原因であるはずがない」と言い張って全体の足を引っ張るやりかたとは異なることに注意してください.客観的な証拠を積み重ねて最終的に「自分の担当ブロックが原因とは思えない」ということが見えてきたとすれば,結論を導き出すために踏んだ切り分けのステップやそこから得られた証拠は,ほかの機能ブロックを作っている人にとっても役に立つ情報になっているはずだからです.
図12に,今までの切り分けの経緯をまとめました.客観的な証拠を積み重ねながら,「自分のブロックが原因かどうか」を基準に切り分けを進めるイメージをつかんでいただきたいと思います
図12 ハングアップ事例の切り分けの全体像
まず,「自分のブロックが原因かどうか」を早期に切り分ける.自分のブロックが怪しいようなら,方式と実装のどちらの問題かの切り分けに着手する.後者なら,リアルタイム性の問題かどうかを確認する.客観的な証拠をロジカルに積み上げて以上の事がらを検証する.