0

シーケンシャル C コードを並列化し、OpenACC (PGI コンパイラ) を使用して NVIDIA GPU にオフロードしようとしています。

私のコードはシーケンシャルコードとして書かれています。以下のように、非常に長い関数を頻繁に呼び出します。

int main()
{
   // blah blah...
   for(i=0; i<10; i++)
   {
      for(j=0; j<20; j++)
      {
          big_function(a,b,c);
      }
   }
   // blah blah...
}

int big_function(a,b,c)
{
   small_function_1(a);
   small_function_2_with_data_dependencies(b);
}

そのような場合、big_function()は GPU で並列化して実行できますか?

#pragma acc kernels を使用して、 for ループ全体を並列領域に宣言しまし た。以下のように。

#pragma acc routine
int big_function(int a, int b, int c);
#pragma acc routine
int small_function_1(int a);
#pragma acc routine
int small_function_2_with_data_dependencies(int b);

int main()
{
   // blah blah...
   #pragma acc data ~~~~
   #pragma acc kernels
   for(i=0; i<10; i++)
   {
      for(j=0; j<20; j++)
      {
          big_function(a,b,c);
      }
   }
   // blah blah...
}

int big_function(a,b,c)
{
   small_function_1(a);
   small_function_2_with_data_dependencies(b);
}

しかし、コンパイルされたファイルが完了するまでに非常に長い時間がかかります。そして、結果は正しくありませんでした。

OpenACC を使用して、多くの関数呼び出しを使用するシーケンシャル コードを並列化できますか?

または、big_function()を分割して小さな部分に分割する必要がありますか?

4

2 に答える 2

1

acc routine例で行ったように、コール ツリーの各関数をディレクティブで装飾する必要があります。すべての並列処理がトップ レベルのループから行われることを期待している場合は、すべてのルーチンをシーケンシャルとしてマークする必要があります ( seq)。あなたがそれをしている限り、コンパイラGPU用にビルドできます。ただし、このような大きな関数呼び出しツリーには多くの状態が含まれる傾向があり、特に GPU リソース、共有メモリ、およびレジスタを消費するため、パフォーマンスが低下する可能性が非常に高くなります。並列処理をコール ツリーの下に移動すると、GPU でのパフォーマンスが大幅に向上することがわかるでしょうが、以前は保存されていたデータを保存する必要があるため、CPU のパフォーマンスに悪影響を及ぼし、メモリ使用量が増加する可能性があります。スレッド状態として利用できます。

実際のコードに関する詳細情報を提供していただければ、正確性の問題のデバッグをお手伝いできます。コンパイラのフィードバック ( -Minfo) をチェックして、コンパイラが想定どおりに動作していることを確認してください。呼び出しツリーによってつまずいていることに気付くかもしれません。また、PGI フォーラムを試すこともできます。多くの場合、問い合わせに対して非常に迅速に対応してくれるからです。

于 2015-08-07T16:01:32.540 に答える
0

コールツリーの深さによって異なります。ジェフラーキンが言っacc routineたように、あなたを助けることができますが、それはそれだけです。一般に、大きなカーネルを作成するには、これらのルーチンをインライン化する必要があります。GPU は、数千行のコードを含む複雑なカーネルを処理するように構築されているわけではありません。

より複雑なケースでそれを行う方法は、i、j ドメインでコールグラフをプライベート化することです (これは、シミュレーションの物理的なパラメーター化であると想定しています)。つまり、1 つの列またはサーフェス ポイントのすべてを計算する代わりに、より高次元のデータをサブルーチンに渡すので、i,j の小さなチャンクを並列化できます。

補足: Fortran 90+用に並列化を行うツールを作成しましたが、残念ながら C++ はサポートされていません。ただし、前処理ソリューションのインスピレーションになるかもしれません。私の場合、CPU パフォーマンスを維持する必要がありました。これは、上記で提案したソリューションで問題になる可能性がありますが、これはあなたの場合には当てはまらない可能性があります。

于 2015-08-08T18:28:50.727 に答える