ウインドリバー 組込みとモバイルソフトウェアの世界的なリーダー
人気ブログご紹介
ブックマーク/共有
ホーム : ウインドリバースクエア : 人気ブログご紹介 : Simics上でのSimicsのデバッグ

人気ブログご紹介  US本社で人気の高い記事をピックアップしてご紹介します。

Simics上でのSimicsのデバッグ

投稿者:Jakob Engblom,, 2012/12/05

私はたびたび書いたり話したりしていますが、Simicsは並列処理のバグのデバッグと、マルチスレッドやマルチコアシステムの障害に対するデバッグには実に有効です。非常に複雑なアプリケーション、具体的に言えばSimics自体の上で、このことを証明した例を最近経験しました。この例は、Simicsの反復の完成度と、複雑なソフトウェアに潜む手ごわいバグを解決する際の有効性の両方の、分かりやすい証明であると考えています。

私はたびたび書いたり話したりしていますが、Simicsは並列処理のバグのデバッグと、マルチスレッドやマルチコアシステムの障害に対するデバッグには実に有効です。非常に複雑なアプリケーション、具体的に言えばSimics自体の上で、このことを証明した例を最近経験しました。この例は、Simicsの反復の完成度と、複雑なソフトウェアに潜む手ごわいバグを解決する際の有効性の両方の、分かりやすい証明であると考えています。

この例の説明は、Simicsに含まれていたバグから始めましょう。ある特定の構成に限って発生するバグがありました。Simicsのターゲットは、プロセッサのシミュレーションをテストする、ベアメタル型テストコードを実行するPowerアーキテクチャマシンです。この構成ではたまに、Simicsまたはモデルに含まれているバグのためにSimicsがクラッシュしました。テストを50 回実行するうちの1回程度しか発生しないので、追跡が難しいバグでした。診断のためにデバッガを接続してバグの再現を試みると、そういうときに限って発生しません(昔からハイセンバグと呼ばれるものです)。

この手の問題を診断する際にSimicsは完璧なツールなのですが、実行するためには、問題が発生するプログラムをSimicsに取り込まなければなりません。すなわち、Simics上でSimicsを実行するのです。まず、Simics内部に開発ホストの複製を作成します。これは何も難しいことではなく、単純に8コアIntelターゲット上に標準的なLinuxのFedora 16をインストールするだけです。 Linuxをインストールしてブートすると、システムのチェックポイントが取得されます。

次に、ホストからの開発コードツリーがTARファイルとしてパッケージングされて、DVDイメージファイルに置かれます。Simicsは、ブートされたターゲットシステムのチェックポイントから起動され、Simics上で稼働しているFedora Linuxは、DVDイメージを仮想DVDドライブに挿入してマウントします。TARファイルは、ターゲット上のファイルシステムにコピーされて展開されます。このようにして、Simicsのインストールが完了すると新しいチェックポイントが取得されて、Simics上でSimicsを実行できるようになります。この時点で得られる成果は、完全に自身で完結していて、制御可能で、再現可能な環境です。

以下のスクリーンショットは、Simics上でSimicsが稼働する様子を示しています。ホストと外部のSimics Fedoraシステムの両方で、同じデスクトップの壁紙を使っています。

次のステップは、Simicsの中にあるバグの再現です。この目的のために、バグに遭遇するまで内部のSimicsを繰り返し実行するシェルコマンドを使用します(このセッションは明らかに、Simicsをインストールした後のチェックポイントから開始します)。

ここでの成果は、バグに遭遇するまでSimicsを実行する準備が整った、この構成です。

ここまでの流れをまとめると、Simics上で稼働するSimicsを構築しました。Powerアーキテクチャ構成の「内部Simics」はホスト上でクラッシュしました。Fedora 16が稼働している「外部Simics」は、開発ホストの仮想レプリカ(ただしSimics内部を除く)を提供しています。

バグの検索とバグの再現の効率を上げるために、スクリプトを追加して外部Simics内で使用しました。

  • そのSimicsスクリプトで、IAターゲットシステムに含まれているプロセッサに割り当てたタイムスライスを変更しました。こうすることで、並列実行プロセスと、SimicsでシミュレートしているFedora 16 OS内のスレッドのスケジューリングに大きな変化が起こり、バグを早く再現する(バグを再現するまでの内部Simicsの実行回数が少なくなる)ことにつながります。
  • 内部Simicsが起動されて、タイミングの変更がIAプロセッサに適用されたら、内部Simicsがテストケースの実行を開始する前にチェックポイントを取得します。これで、バグに直接つながるチェックポイントが利用できます。バグの再現のためにターゲットのウォームアップや、Simicsを特定の構成にする必要は全くありません。チェックポイントは結果的に、この問題に関する自己完結したバグレポートとなります。
  • 内部Simicsのsegfault(セグメントエラー)ハンドラにマジック命令(ブルースター)を埋め込みます。これで、内部Simicsのクラッシュは簡単に捕捉できます。正しいページフォルトの捕捉を試みたり、正しい場所にブレークポイントを設定するよりも、このようにマジック命令を使用する方が簡単な場合があります。マジック命令とは、コード中でバイオマーカーのような役割を果たすもので、デバッグ情報やOS Awarenessに関係なく常にトリガーの働きをします。しかも、マジック命令は起動するまでオーバーヘッドは発生しません。

ついに、内部Simicsを20回程度実行すると、バグをトリガーできるようになりました。チェックポイントとSimicsの反復能力によって、バグの再現は困難ではなくなりました。Simicsのクラッシュは、もはやいつでも再現できるようになったので、次はデバッグに移って、Simicsがクラッシュする理由を考えることにしましょう。たまにしか起こらないハイセンバグは、100%再現可能なボーアバグに変わりました。

デバッグの最初のステップは、内部Simicsの中に多数ある、動的にロードされたモジュールのマッピングについて考えることです。これは、外部Simicsを稼働させてFedoraシェルにCtrl-Zを送信し、内部Simicsを一時停止させることで実現します。このとき、Simics上で動作しているFedora Linux上の/procファイルシステムに、ロードアドレスを検出するための応答指令信号が送られます。Simicsが起動した後にチェックポイントが取得されているので、これはチェックポイント中で検出される、ソフトウェア構成内のマッピングであることが分かります。チェックポイントがオープンされるたびに、同じマッピングが適用されます。こうして情報が保存され、使用しているSimicsモジュールのためのシンボリックデバッグ情報を設定するために利用されます。

デバッグの次のステップでは、チェックポイントを再びオープンし、そこからリバース実行を始めて、マジック命令がヒットするまで実行を続けます。ここで、segfaultハンドラが実行される前に内部Simicsが動作していた最終時点のバックアップを取得するために、OS awarenessが利用されます。これによって外部Simicsは、内部Simicsのクラッシュを引き起こした命令とまったく同じ命令を実行します。

Simicsは、コードが存在しないロケーション(BCDE)でコードの実行を試みていたことが判明しました。

そこから1命令戻ると、BCDEロケーションへのJMP命令を実行していました。

では、このJMP BCDE命令を実行するに至った理由は何でしょう。この命令は明らかに、Simicsの静的コードには含まれていませんが、Simics自身が命令実行中に何か生成したと考えられます(SimicsにはJITコンパイラが含まれているので、実行中にコードを変更する可能性は、十分にあります)。

誤ったJMP命令が作成された状況を調べるために、命令(JMP BCDE)にメモリー書き込みブレークポイントを設定して、リバース実行を進めてみました。Simicsは、命令の「JMP」部分をメモリーに書き込んだ時点で停止しました。ここでスタックのバックトレースを実行して、コードはJITが生成したコードストリームに5バイトの「JMP XYZQ」命令を書き込もうとしていたことが分かりました。JMP命令コードを含むバイトの書き込み時にブレークポイントがヒットしたことから、命令が実行されてSimicsがクラッシュしたとき、命令以外の4バイト(JMP命令が本来目指していたロケーションであるXYZQ)はまだ書き込まれていなかったことが分かります。

命令を(プロセッサ上で)書かれている順序どおりに1ステップずつ実行することで、内部Simicsの中でスレッドの切り替えが起こり、入ってきたスレッドが即座に5バイトのJMP命令を実行して現在の問題が起こったと判明しました。JMPバイトだけが書き込まれていたことから、狙っていたXYZQ(もともとのABDCEコードを実行するにはそれでもよかった)へのジャンプではなく、BCDEへのジャンプとなってしまったことが分かります。したがって、今回の状況は、読み取りはメモリーの内容をコードに書かれたとおりに実行して、書き込みは通常のデータの書き込みを行うという性質に基づいた、読み取りと書き込みの競合条件の問題であると診断されました。問題が特定されれば、その修正はとてもたやすいことでした。

同じ構成でSimicsの競合条件がもう1つ見つかり、それも修正されました。さらに頻度の高いケースである複数のスレッドの同時実行に関係する問題で、共有しているデータ構造の更新および読み取りを実行する間に同期が不完全になるというものでした。

要約すると、このブログエントリーでは、Simicsを利用して、現実世界に存在する複雑なソフトウェアシステムの1つでもあるSimicsの、並列実行のバグを検出して修正した一例を説明しました。成功のカギとなったのは、Simicsが備えている反復能力です。タイミングが関係する、たまにしか発生しないイベントにも対応できますし、チェックポイント、スクリプティング、リバース実行、デバッグ設備と連携させることもできます。

原文はこちら:http://blogs.windriver.com/m2m/2012/12/biggest-predictions-for-m2m.html
本社ブログサイト:http://blogs.windriver.com/

人気ブログご紹介 »
ページの先頭へ戻る »