大規模並列スーパーコンピュータ上で実行される高性能コンピューティングアプリケーションは、マルチスレッド、マルチプロセスモデルを使用して設計された並行プログラムで構成されています。アプリケーションは、さまざまな並列度を持つさまざまな構成要素(スレッド、ローカルプロセス、分散プロセスなど)で構成される場合があります。高性能並行プログラムは、逐次プログラムと同様の設計パターン、モデル、および原理を使用しますが、逐次プログラムとは異なり、通常は非決定的な動作を示します。さまざまな並列構成要素間の相互作用の数が増えるにつれて、バグが発生する可能性が高くなります。競合状態、データ競合、デッドロック、シグナルの欠落、ライブロックは、一般的なエラーの種類です。
並列プログラムは、大きく分けて明示的並列と暗黙的並列の2種類に分類できます。プロセス生成、通信、同期のために定義された並列言語構造を使用することで、アプリケーションは明示的に並列化されます。一方、ツールや並列化コンパイラを使用して逐次プログラムを並列プログラムに変換すると、暗黙的に並列化されます。どちらのカテゴリも、バグが発生しやすいという点では同じです。
並行アプリケーションは、基盤となるオペレーティングシステムのあらゆるスレッドスケジュールで正しく実行される必要があります。しかし、従来のテスト方法では、主にハイゼンバグ[ 1 ]の問題のために、バグを検出できるのはごくわずかです。ハイゼンバグとは、同期要求や遅延ステートメントなどの構造を追加してデバッガ で分離して調査しようとすると、変化したり消えたりするエラーのことです。
もう一つの問題は、スケジューラの予測不可能な動作に起因します。システム負荷の違いはスケジューラの動作に影響を与えます。この動作は手動で変更することはできません。この不確定性に対処するには、さまざまな実行環境でプログラムを何度も実行する必要があります。それでも、バグが再現できるとは限りません。ほとんどの場合、プログラムは正しく実行され、バグは特定の条件が一致した場合にのみ現れます。結果として、並行プログラムの再現性の低さは、エラー検出の大きな障害となります。例として、以下を考えてみましょう。
明らかに、これはデッドロックを引き起こすという問題を抱えている。しかし、プログラムの実行によってはデッドロックが発生する場合もあれば、正常に実行される場合もある。
プローブ効果は、同期の問題を抱える並列プログラムに遅延文を挿入した際に発生します。この効果は、ハイゼンバグと同様に、動作の変化を引き起こし、問題を隠蔽する可能性があります。プローブ効果の原因を特定することは、並列アプリケーションのテストにおいて大きな課題となります。プローブ効果とハイゼンバグの主な違いは、ハイゼンバグはテスト中に並行アプリケーションに遅延文や同期要求を追加した際に発生するのに対し、プローブ効果は開発者が同期が不十分な並行アプリケーションに遅延文を追加した際に発生する点です。
逐次プログラムと並行プログラムの違いは、テスト戦略の違いにつながります。逐次プログラムの戦略は、並行アプリケーションに適するように変更できます。特殊な戦略も開発されています。従来、テストにはテストケースの設計と、プログラムが期待どおりの結果を生成することの確認が含まれます。したがって、仕様、機能などのエラーは、アプリケーションを実行し、機能テスト、ホワイトボックス、ブラックボックス、グレーボックスなどのテスト方法を適用することによって検出されます。[ 2 ]静的解析は、データフロー解析、制御フロー解析、循環的複雑度、スレッドエスケープ解析、静的スライシング解析などの方法を使用して問題を見つける、高性能ソフトウェアのエラーを検出するためにも使用されます。機能テストの前に静的解析を使用すると、時間を節約できます。「エラーが何であるか」を検出して、エラーソースを見つけることができます。静的解析技術は、同期の欠如、不適切な同期、デッドロックの発生、ランデブー要求でのポストウェイトエラーなどの問題を検出できます。
詳細:
スケジューリングの不確定性には2つの原因がある。[ 1 ]
並行プログラムの再現性を確保するために、外部スケジューラが使用されます。テスト対象プログラムは、このスケジューラへの呼び出しを追加するようにインストルメンテーションされます。このような呼び出しは、各スレッドの開始時と終了時、およびすべての同期要求の前に行われます。このスケジューラは、各スレッドに関連付けられたセマフォを維持することにより、実行スレッドを選択的にブロックし、任意の時点で実行可能なスレッドが1つだけになるようにします。このようにして、並列非決定性アプリケーションを直列実行シーケンスに変換し、再現性を実現します。直列化スケジューラによって行われるスケジューリング決定の数は、次式で与えられます。
(N * K / P)*{(N + P)!} ここで、 N = スレッド数、 K = 潜在的なコンテキストスイッチポイント、 P = プリエンプティブコンテキストスイッチの予算決定論的スケジューリングを使用してより正確な結果を得るには、別の方法を選択できます。並行プログラムに適切な場所にプリエンプションをいくつか配置すると、データ競合に関連するバグを検出できます。[ 1 ]バグはクラスターで見つかります。1 つのバグが存在すると、同じコード領域にさらに多くのバグが存在する可能性が高くなります。したがって、テスト プロセスの各パスで、バグのあるコード セクションが特定されます。次のパスでは、スケジューラ呼び出しを周囲に追加することで、これらのセクションをより徹底的に精査します。問題のある場所を異なる順序で実行できるようにすると、予期しない動作が明らかになることがあります。
この戦略により、アプリケーションがプローブ効果の影響を受けにくくなります。プローブ効果を引き起こすエラーの原因は、タスク作成の問題から同期や通信の問題まで多岐にわたります。タイミング関連のテストの要件: [ 3 ]
入力データセットごとのテストケース数は次のとおりです。
n C 1 + n C 1 + … + n C 1 = 2 n -1 ここで、n は同期、プロセス作成、通信呼び出しの総数です。
この方程式は指数関数的なオーダーを持つ。テストケースの数を減らすために、決定論的実行法(DET)または多重実行法(MET)のいずれかが用いられる。対処すべき様々な問題がある。
この方法は、定義と使用のペアという概念を適用して、テスト対象となるパスを決定します。
ソフトウェア検証とは、ソフトウェアが正しく動作し、設計どおりに意図されたタスクを実行していることを証明するプロセスです。
既知の結果を生成するために、システムに入力が与えられます。この入力と結果のペアは、以前の経験的結果や手動計算から取得できます。[ 4 ]これは、関連するすべてのモジュールが統合されている場合にのみ実行できるシステムレベルのテストです。さらに、バグが存在することを示すだけで、バグの数、場所、性質に関する詳細な情報は提供しません。
これらのテストは主に科学シミュレーションに使用されます。シミュレーションの出力は予測できないことがよくあります。これらのシミュレーションは科学法則を記述しようとするため、理論における対称性はシミュレーションによって尊重されなければなりません。したがって、対称性の線に沿って入力条件を変化させ、得られた結果を外部から得られた結果と比較することにより、バグの存在を検出できます。[ 4 ]

科学計算では、ほとんどのデータはシミュレーション条件の中央領域に集中しています。そのため、リアルタイムの実験データで境界値テスト[ 2 ]を実行することは困難です 。そこで、境界条件を効果的にテストするために、シミュレーションの中心(例えば、図1のデータ値10の場合)を境界のいずれかに移動させます。
並列実装テストは通常、メッセージパッシングなどの分散メモリプログラミングモデルを使用するアプリケーションに使用されます。これらのテストは、プロセッサの規則的なグリッドを使用するプログラムによく適用されます。[ 4 ]
多くの並列データベースは、クエリを実行するために分散並列処理を使用します。合計などの集計関数を実行する際には、次の戦略が使用されます。 [ 5 ]
最終結果には、各プロセッサがローカルの結果を個別に丸めるため、丸め誤差が含まれる可能性があります。このような誤差が発生しないことを確認するテスト方法の一つは、集計合計が分解に依存しないことを示すことです。別の集計方法として、個々の値をすべて一つのプロセッサに送信して合計する方法があります。この結果を分散処理の結果と比較することで、一貫性を確認できます。
このツールは、決定論的スケジューリングを使用して非決定性を排除します。以前に実行されたスケジュール パスを追跡し、新しいスケジュール パスが実行されるたびに保証します。[ 1 ]
{{cite book}}: CS1メンテナンス: DOIは2025年7月現在非アクティブです(リンク)