OPenMP* parallel 領域と task 構造をグラフにマップするには、fgt2xmlコンバーターを--omp_experimentalオプション付きでビルドする必要があります。このようなグラフでは、ノードは並列領域とタスクを表し、エッジはタスクの依存関係を表します。
すべての OpenMP* に関連する並列処理は、OpenMP* 並列領域内に含まれています。フローグラフ・アナライザーでは、並列領域はグラフキャンバスのサブグラフ・ノードにマップされます。サブグラフノードは少なくとも 2 つのノードで構成されます。
例えば次のような空の並列領域の場合、フローグラフ・アナライザーは、omp0::n0などのサブグラフノードをグラフキャンバスに作成します。
#pragma omp parallel { }
サブグラフノードをダブルクリックすると次のように表示されます。ここで、omp0::n0::n1は並列領域の始まりであり、omp0::n0::n2はノードの最後にある暗黙のバリアです。
OpenMP* タスクは、同じ領域の他のタスクと同時に実行できる並列領域に含まれるコードブロックです。フローグラフ・アナライザーでは、OpenMP* タスクは汎用ノードにマップされます。例えば、次のコードには 2 つのタスクがあり、1 つは hello を出力し、もう一方は world で指定されたディレクトリーにプロジェクトが作成されます。これらのタスクの実行順序は指定されていないため、任意の順番で実行されます。しかし、2 つのタスクは常に、外部の並列領域が領域の入り口で開始され、その領域が終了する前に完了します。
#pragma omp parallel { #pragma omp task { printf("hello "); } #pragma omp task { printf("world "); } }
このプログラムをフローグラフ・アナライザーで視覚化すると次のようになります。
このサブグラフをダブルクリックすると、次のように表示されます、ここで、omp0::n0::n1は並列領域の始まり、omp0::n0::n4は領域最後の暗黙のバリア、omp0::n0::n2は "hello" タスク、そしてomp0::n0::n3は "world" タスクです。
OpenMP* 仕様では、タスクの部分的な順序付けをdepend節で表現できます。先行するタスクが完了すると、タスクの依存関係は完結します。OpenMP* API でサポートされる依存関係タイプは、in、out、in-out の 3 つあります。
フローグラフ・アナライザーでは、タスクの依存関係は OpenMP* タスクを示すノード間のエッジで表現されます。
フローグラフ・アナライザーで視覚化される依存関係を正しく理解することが重要です。
タスク依存関係グラフは、アプリケーションで実行される OpenMP* タスクのdepend節で設定される部分的な順序付けを表します。グラフのノードは OpenMP* タスクであり、エッジは部分的な順序付けを表します。
グラフが複雑にならないように、フローグラフ・アナライザーはいくつかの遷移を示す依存関係を省略します。遷移的な依存関係とは、3 つのタスク間の依存関係であり、最初のタスクと 2 番目のタスク間、および 2 番目のタスクと 3 番目のタスク間に依存関係が成立する場合、最初のタスクと 3 番目のタスク間でも依存関係は成立します。次の図では、位置 x に a <x b の関係で依存しているため、ノード a はノード b の前に部分的な順序付けをして実行する必要があります。
図の (a) は、ある場所 x の依存関係のみを含む例を示しています。a <x b かつ b <x d であるため、フローグラフ・アナライザーは [transitive (移行)] エッジ a <x d を表示しません。
図の (b) は、部分的な順序付けを決定する 2 つの位置 x と y を示しています。a から d への依存関係エッジは、a <x d と a <y d の 2 つが考えられます。フローグラフ・アナライザーには、d の y の直接のソースであるため、a から d へのエッジが含まれますが、a <x d は除外されます。
以下に例を示します。
#pragma omp parallel { std::string s = ""; #prgma omp single { #pragma omp task depend( out: s) { s = "hello"; printf("%s", s); } #pragma omp task depend( out: s ) { s = "world"; printf("%s",s); } } }
このアプリケーションをフローグラフ・アナライザーで視覚化すると、OpenMP* 並列領域を表す単一の最上位サブグラフノードが表示されます。
サブグラフをダブルクリックすると次のように表示されます。
omp0::n0::n2 と omp0::n0::n3 の間のエッジは、変数 s の依存関係がタスクにあることを表します。
フローグラフ・アナライザーの主なコンポーネントには、ツリーマップ・ビュー、グラフ・トポロジー・キャンバス、タイムラインと同時実行分布図ビュー、クリティカル・パス・レポートが含まれます。OpenMP* タスクトレースは、これらのビューに自動的にマッピングされます。
詳細については、 https://link.springer.com/chapter/10.1007/978-3-319-98521-3_12 (英語) をご覧ください。
OpenMP* タスクの依存関係グラフのグラフィック表示に加えて、フローグラフ・アナライザーはノードを対応するソースコードへマッピングして表示します。この情報を得るには、OpenMP* アプリケーションを-gオプション付きでビルドする必要があります。
例えば、並列領域のサブグラフノードを使用したソースコードの対応付けは、次のようになります。