プログラミングの 50% はデバッグに費やされていると言われています。本製品は、このデバッグに掛る時間を大幅に短縮します。デバッグに多くのコストが掛っている企業は、問題を素早く解決するために Linaro DDT を利用することをお勧めします。
Linux で動作する C/C++、Fortran 90 アプリケーション向けのデバッガーである Linaro DDT は、より効率的な開発を支援します。マルチスレッド/マルチプロセスのアプリケーションのデバッグが可能であり、複雑に関連しているコンポーネント間のデバッグを容易にします。
本製品は、開発ツールスイートである Linaro Forge に含まれています。
ますます並列化が進んでいくプロセッサー、クラスター、スーパーコンピューターを活用するために開発されたソフトウェアのデバッグは複雑になりがちです。本製品の強力で直観的な GUI や配列を可視化する機能などにより、複雑なデバッグは単純化されます。
コマンドラインを利用する熟練者向けに、自動変数比較機能やインプロセスのメモリ デバッグ機能は単一のコマンドで利用可能です。事後分析に役立つように、リッチテキスト形式/テキスト形式でのログ ファイルも生成されます。
新しいアーキテクチャやシステムに移行する際に、新たなツールの利用方法を学ぶ必要が無いことは大きなメリットです。Linaro DDT はあらゆる環境、ノートパソコン、最新のスーパーコンピューター、次世代のアーキテクチャで動作します。Arm、NVIDIA CUDA、IBM BlueGene/Q、OpenPOWER をサポートします。
Linaro DDT は、開発者のデバッグにかかる時間を短縮し、ソフトウェアのタイムリーな完成を支援します。この包括的な C/C++、Fortran、Fortran 90 向けのマルチプロセス/マルチスレッド アプリケーション用デバッガーを使うことにより、次のことが実現できます:
MPI や OpenMP* などのライブラリを使用したマルチプロセスやマルチスレッドの開発する場合、Linaro DDT を使うことで並列処理の実装が容易になります。
DDT は、優れたデータ収集機能や差異のハイライト表示機能によってプログラムの状態を自動的に比較できるため、複数のコンテキストをすばやく処理できます。
並列スタック ビューにより、少数のものから数百、数千にいたるスレッドおよびプロセスのスタックをスケーラブルに表示できます。スタックをグループ化し、ダイバージェンスを示唆する差異をハイライトするため、MPI や OpenMP*、pthreads、CUDA および OpenACC などのデバッグに最適です。
優れたハイライトおよびスパークライン機能で各プロセスにおける変数値をサムネイル表示するため、通常と異なるデータの値やデータの変更を瞬時に確認できます。スパークラインに関する詳細は、ブログを参照してください。さらに、プロセスやスレッド間の比較ツールにより、データのグループ化や検索が容易になります。
DDT では、広く普及している MPI 規格のメッセージ キューをデバッグし、マルチプロセスのコードにありがちなタイプのバグを見極める役に立ちます。
Linaro DDT は、実証済みの非常に高速なパフォーマンスで、700,000 のプロセスを瞬時にステップ実行し、表示します。
Linaro DDT を使うと、変数を表示して複雑なデータ構造体を把握するという必要不可欠な作業が容易になります。
C++、Fortan 関連の機能については、C++ debugging、 Fortran debugging ページを参照してください。
DDT の組み込みメモリ デバッガーは、ヒープ メモリの使用における問題を自動的に表示します。
詳細は、メモリ デバッグ ページを参照ください。
デバッグに成功すると、コードの高速化が期待されます。Linaro DDT は、開発ツール スイートである Linaro Forge の一部です。DDT は単一ツールとして、または Linux* 上での並列/マルチスレッド コードの代表的なプロファイラーである Linaro MAP (Linux parallel and threaded code profiler、 Linaro MAP) を含む Linaro Forge ライセンスの一部としても入手可能です。MAP は、DDT と同じユーザー インターフェースおよびインストールを使用しているため、デバッグ後簡単にコードのプロファイルへ移行できます。
開発者は、パワフルなユーザー インターフェースでデバッグ作業と同時に編集、ビルド、そしてコミットすることができます。
リモート システムを使用する場合でも、Mac や Windows®、Linux* クライアントのノートパソコンからリモート クライアントを使って問題なく接続できます。
Linaro DDT はベスト プラクティスを統合し、デバッグに費やす時間を削減し、より迅速に問題の原因を明らかにします。
Linaro DDT のログ ブックには作業中に踏んだステップがすべて記録されるため、デバッグの進捗管理も簡単です。
トレース ポイントを使うことで、スケーラブルな printf デバッグが実現します。DDT では、コードにトレース ポイントを挿入し、コード 1 行ごとにその値をログします。結果は、対話的にまたはオフライン デバッグ モードで利用可能です。
オフライン モードでは、スリープ中でもデバッグできます。バッチ スケジューラーを利用してコマンドラインからオフライン デバッグの実行をスケジュールすると、ジョブの完了時に DDT からテキストまたは HTML 形式のエラーおよびトレース レポートが送信されます。オフライン デバッグに関する詳細は、ブログを参照してください。
DDT は、科学計算および技術計算における膨大なデータセットの処理を実現できるように設計されています。複数のプロセスに分散している場合でも、巨大な配列の表示またはフィルタリングができます。
Linaro DDT はクロスプラットフォームに対応しており、現在使われている主要な技術計算プラットフォームをすべてサポートしています。1 つの製品で CUDA デバッグ (CUDA debugger)、並列デバッグ、マルチスレッド デバッグ、OpenMP* プログラムのデバッグおよびメモリ デバッグ (memory debugger) 機能のすべてを備えており、ハイブリッド型のプログラミング モデルをサポートしています。
Linaro DDT のメモリ デバッガーは、Linux* 上での C/C++、および Fortran コードにありがちな多くのメモリ エラーの修正を支援します。このモードの機能は、コマンドライン デバッガーや print 文によるデバッグよりもはるかに優れています。
メモリ デバッグは、DDT のチェック ボックスをオンにするか、コマンドラインに "--mem-debug" を追加することで有効になります (Cray XC もしくは XK プラットフォームに関しては、リンクするためのさらなるステップが必要となります)。
Linaro DDT を使うことにより、次のような課題の答えを見つけ、問題を解決することができます:
これらの課題の答えを見つけることで、予期せぬクラッシュを防ぐことができます。ここに挙げられた課題を解決することは、ソフトウェアの品質改善にもつながります。
メモリ デバッグ モードによって検知されるメモリの領域をヒープといいます。ヒープとは、C では malloc、free、その他類似の関数、C++ では new/delete オペレーター、Fortran 90 あるいはそれ以降の Fortran 派生言語においては allocate/deallocate などのプリミティブ型によって管理されている領域を指します。
DDT は、これらの関数をインターセプトしてエラーを検出し、情報を記録し、またメモリがどれだけ使用されているかを測定します。
チェックのレベルは、メモリ デバッグの設定ダイアログにある設定レベルでベーシック モードからフル モードに調節できます。フル モードでは、割り当て数の多いコードのスピードを下げる可能性がありますが、ベーシック モードでは時間的なコストはほとんどありません。
メモリの総使用量に注目することは重要です。メモリを過度に割り当てた結果、プロセスがオペレーティング システムに強制終了されてしまうことも考えられます。
プロセスのメモリ使用量は、[Tools (ツール)] > [Overall Memory Stats (全体のメモリ統計)] メニューで表示できます。 複数のプロセスをデバッグする場合には、それぞれのプロセス (または使用度の高いプロセス群) は、右のように表示されます。
この表示画面は、メモリ デバッグ機能が有効化されている場合に利用できます。総使用量が上昇した場合には、メモリ リークが示唆されます。
DDT を含むツール スイート、Linaro Forge にも、パフォーマンス プロファイラーである MAP の機能としてメモリ プロファイリングが存在します。MAP では、メモリの使用状況が変化する様子がグラフィック表示されますので、いつどこでメモリの使用量が増加したのかを絞り込むことができます。
メモリが割り当てられた後に解放されなければ、結果的にメモリ不足の問題が生じ、突然プログラムが終了してしまいます。
メモリ リークは、メモリ デバッグが有効化されている場合、[Tools (ツール)] > [Current Memory Usage (現在のメモリ使用量)] メニューで検出できます。
割り当てられたメモリに対し、DDT は個別にスタック トレースおよび指定した割り当てサイズを記録します。これにより、コードのどこで割り当てがなされ、どれだけのメモリを使用しているかが確認できます。
[Current Memory Usage] ダイアログはこの情報を使い、使用バイト数を単位とした呼び出しの先頭の位置をグラフに描画します。リークが起こった場合には、この棒グラフにはっきりと表示されます。棒グラフの要素をクリックするとポインターがリストアップされ、さらにその中からポインターを選択すると、その割り当てのスタックとサイズが表示されます。
多くのコードは少数のエントリー ポイントを介して割り当てを行っています。
たとえば、メモリの割り当てには C++ クラスのコンストラクターがよく使用されます。プログラム中を通して、最も有用なクラスが呼び出されます。この場合、コンストラクターを呼び出したコード行によって割り当てをグループ化すると、コンストラクターの呼び出しが不定形な塊としてひとまとめにされないためより有益です。
コンストラクターの呼び出しごとにグループ化するには、棒グラフのブロックを右クリックし、その関数を “Custom Allocator (カスタム アロケーター)” として追加します。その関数の呼び出しは、呼び出し位置によって個別にグループ化されます。
DDT には、上記で説明した [Current Memory Usage] ツールの対話型情報に類似した、非インタラクティブ型のメモリ デバッグ モードがあります。このモードは、メモリの使用量を測定し、リークが実動コードに入り込まないことを自動的に保証するため、夜間テスト中や CI サーバーなどでよく使われます。
このモードでは、プロセスの終了後にも残されたままとなっているメモリの割り当て情報が記載された HTML ファイルが作成されます。
ddt --offline offline-log.html --mem-debug ... application.exe ....
これにより、プログラムの実行中にログされた重大なデバッグ イベントやリーク レポートを含む、非インタラクティブ モードにおけるデバッグ セッションの注釈付きログ ファイルが作成されます。
すでに解放されている割り当てや、割り当てられていない、または正規のヒープ領域に到達していない偽のアドレスを解放しようとする時にもクラッシュが起こる場合があります。
結果として即時終了、ヒープ コラプション、あるいは将来的なクラッシュにつながります。
DDT では、無効なポインターが検出されると即エラーメッセージがトリガーされ、エラーの起こった正確な場所でプロセスを停止するので、このような問題を回避することができます。
ダングリング ポインターとは、解放されたものの null に設定されていないメモリのポインターのことを指します。あとに続くコードがダングリング ポインターを使い続けると、データはまるで有効に見えますが、ある時突如としてメモリが別の場所に再割り当てされてしまう可能性があります。
ダングリング ポインターは、予期できない動作、サイレント データ コラプション、またはプログラムのクラッシュを引き起こす原因となります。
ダングリング ポインターの検出機能を有効にするには、メモリ デバッグが Fast よりも 1 つ上のレベルに設定されている必要があります。[Enabled Checks] ウィンドウに “free-protect” という言葉が表示されます。
ダングリング ポインターの問題を検出するには、通常はこのレベルのメモリ デバッグで十分だと考えられます。ダングリング ポインターが再使用されると、再利用したコードで正確にプログラムが停止し、次のようなエラー メッセージが表示されます:
デバッガーでは、どのポインターがダングリングしていて、もともとそれがどこで割り当てられたのかも表示されます。いずれかのポインターまたは動的に割り当てられた配列を右クリックし、メニューから [View Pointer Details (ポインターの詳細情報を表示)] を選択します:
Linaro DDT では、どの特定のポインターがダングリングしているかが直ちにわかり (ポインターがすでに解放された割り当てを指していることを示します)、その割り当てに起因する関数呼び出しのフルスタックを表示します。
上のダングリング ポインターのセクションで説明したとおり、[Pointer Details] ウィンドウにはポインターに関する詳細情報が表示されます:
特に上の画像では、ポインターが hello.c:88 で割り当てられたということが確認でき、そこをクリックすることで直ちにソース コード ビューアー内でその場所に移動できます。
このメモリがどこで解放されたのかを知ることもできます。
配列範囲外またはその他のメモリの割り当て範囲外で値を読み取ることは、好ましいことではありません。
大半の場合には見過ごされ、問題が発生しないこともありますが、ランタイム環境でのごく僅かな変更がクラッシュの有無を左右し、断続的なクラッシュを引き起こす可能性もあります。
DDT では、このようなエラーを回避できます。オペレーティング システムに働きかけて各割り当ての前後にページを作成し、それぞれを読み取り/書き込み禁止にします。保護されているメモリに読み取りまたは書き込み操作が行われようとすると、Linux* オペレーティング システムがデバッガーに通知します。これらのページは "ガード ページ" または "レッド ゾーン" として知られています。
大半の科学計算を行うコードや Fortran 90 コードなど、大きな割り当ての比較的少ないコードに関しては、ガード ページとして使われるページ数も少なくなります。
C++ コードは、概して小さい割り当てを大量に使用しますので、プロセス リミットに到達してしまう可能性があります。そのようなコードに関しては、DDT では、“フェンス チェッキング” または “フェンス ペインティング” として知られる 代替設定を提供しています。この設定では、割り当てメモリの上下数バイトを定期的に検証し、予期しない書き込みがされていないかを確認します。このモードがチェックするのは書き込みだけで、誤った読み取りは検出できないため、可能な限りガード ページ モードの方が優先的に使用されています。