ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
Oracle Solaris Studio 12.3: OpenMP API ユーザーガイド Oracle Solaris Studio 12.3 Information Library (日本語) |
OpenMP アプリケーションのパフォーマンスを向上させる一般的なテクニックとして、次のようなものがあります。
同期を最小限に抑える。
できる限り、BARRIER、CRITICAL 領域、ORDERED 領域、ロックの使用を回避してください。
可能な場合は NOWAIT 節を使用して、冗長または不要なバリアを取り除いてください。たとえば、並列領域の最後につねに暗黙のバリアがあります。領域の最後の DO に NOWAIT を追加することによって、1 つの冗長なバリアが取り除かれます。
名前付きの CRITICAL 領域を使用して、きめの細かいロックを行なってください。
明示的な FLUSH の使用には注意してください。フラッシュは、データキャッシュの内容をメモリーに退避させ、以降のデータアクセスで、メモリーからの再読み込みが必要になることがあります。このすべてが効率の低下になります。
デフォルトでは、アイドル状態のスレッドがある時間経過後にスリープします。タイムアウト期間の終わりまでに作業が見つからない場合、スレッドはスリープ状態になり、ほかのスレッドを犠牲にしてプロセッササイクルを浪費することを回避します。デフォルトのタイムアウト期間がアプリケーションに対して不十分な場合、スレッドがスリープするのが早すぎたり、遅すぎたりすることがあります。通常、アプリケーションが専用のプロセッサで実行される場合は、SPIN によって最適なアプリケーションパフォーマンスが得られます。アプリケーションがほかのアプリケーションと同時にプロセッサを共有する場合は、デフォルトの設定、またはスレッドをスピンさせておく時間の長すぎない設定が、システムのスループットにとって最適です。SUNW_MP_THR_IDLE 環境変数を使用するとデフォルトのタイムアウト期間を上書きでき、アイドル状態のスレッドがスリープすることなく、常にアクティブなままにすることもできます。
外側の DO/FOR などをできる限り並列化させてください。1 つの並列領域で複数のループを囲みます。一般に、並列化のオーバーヘッドを抑制するには、並列領域をできる限り大きくします。たとえば、この構文では効率が低くなります。
!$OMP PARALLEL .... !$OMP DO .... !$OMP END DO .... !$OMP END PARALLEL !$OMP PARALLEL .... !$OMP DO .... !$OMP END DO .... !$OMP END PARALLEL
次の構文の方が効率が高くなります。
!$OMP PARALLEL .... !$OMP DO .... !$OMP END DO ..... !$OMP DO .... !$OMP END DO !$OMP END PARALLEL
並列領域では、ワークシェアリング DO/FOR 指令ではなく、PARALLEL DO/FOR を使用してください。複数のループが含まれることがある一般的な並列領域よりも、PARALLEL DO/FOR を実装した方が効率的です。たとえば、この構文では効率が低くなります。
!$OMP PARALLEL !$OMP DO ..... !$OMP END DO !$OMP END PARALLEL
この構文の方が効率が高くなります。
!$OMP PARALLEL DO .... !$OMP END PARALLEL
Oracle Solaris システムでは、SUNW_MP_PROCBIND を使用してスレッドをプロセッサに結合してください。static スケジュール指定ととともにプロセッサ結合を使用すると、並列領域の前回呼び出し以降、その領域内のスレッドがアクセスするデータがローカルキャッシュに存在する、特定のデータ再利用パターンを持つアプリケーションにメリットがあります。「2.3 プロセッサ結合」を参照してください。
可能な場所では、できる限り SINGLE ではなく、MASTER を使用してください。
MASTER 指令は、暗黙の BARRIER のない IF として実装されます。 IF(omp_get_thread_num() == 0) {...}
SINGLE 指令は、ほかのワークシェアリング構文に似た実装になります。どのスレッドが最初に SINGLE に達するかを記録するのは、実行時のオーバーヘッドの増加になります。NOWAIT が指定されていない場合は暗黙の BARRIER があり、効率が低くなります。
適切なループスケジュール指定を選択してください。
STATIC は同期オーバーヘッドの原因にならず、データがキャッシュに収まったとき、データのローカル性を維持できます。ただし、STATIC は、負荷の不均衡をもたらすことがあります。
DYNAMIC,GUIDED は、どのチャンクが割り当てられたかを記録するため、同期オーバーヘッドを招き、そのスケジュールによってデータのローカル性の低下をもたらすことがあります。ただし、負荷均衡が改善することがあります。チャンクのサイズを変えて試してください。
オーバーヘッドが大きくなる可能性があるため、LASTPRIVATE の使用には注意してください。
並列構文からの復帰時、データを占有領域から共有領域にコピーする必要があります。
コンパイル済みのコードは、どのスレッドが論理的に最後の反復を実行したか確認します。つまり、並列 DO/FOR 内の個々の分割単位の終わりで余分な仕事が生じることになります。分割数が多いと、オーバーヘッドが増加します。
効率的なスレッドセーフのメモリー管理を使用してください。
アプリケーションが明示的に、あるいは動的/割り当て可能な配列やベクトル化された組み込み関数などのコンパイラ生成のコードで malloc() および free() が使用されていることがあります。
libc にあるスレッドセーフな malloc() および free() には、内部ブロックを原因とする大きな同期オーバーヘッドがあります。libmtmalloc ライブラリでは、より高速のバージョンが提供されています。libmtmalloc ライブラリを使用するには、リンクに -lmtmalloc を使用してください。
データが小さい場合、OpenMP の並列ループが十分に機能しないことがあります。PARALLEL 構文では IF 節を使用して、ある程度のパフォーマンス向上が期待できる場合にのみループを並列実行させるように指定します。
可能であれば、ループをマージしてください。たとえば、2 つのループをマージします。
!$omp parallel do do i = ... ..........statements_1... end do !$omp parallel do do i = ... ..........statements_2... end do
1 つのループにマージされました。
!$omp parallel do do i = ... ..........statements_1... ..........statements_2... end do
アプリケーションにある程度以上のスケーラビリティーがない場合は、入れ子並列処理を試してください。OpenMP での入れ子並列処理についての詳細は、「1.2 特別な表記」を参照してください。