tech::hexagram

personal note for technical issue.

OpenMP+アンローリングでプログラムの高速化を図る

引き続き研究ネタ.

大量の計算をプログラムで実行する場合,なんとかして高速化を図りたいということは往々にしてあるかと思います.

そこで,比較的実装が簡単で効果があるOpenMPとアンローリングについて今日は書いてみたいと思います.

アンローリングとは

アンローリングとは,for文のループ内を少しいじることでプログラムの高速化を図る手法です.

例えば,こんな感じ.

#include <stdio.h>

int main(void){
  int i,j;
  double c;
  for(i=0;i<100;i++){
    for(j=0;j<100;j++){
      c=calc(i,j) //i,jを使ったなんかの計算
  }}
}

これを,アンローリングを使うと以下のようになります.

#include <stdio.h>

int main(void){
  int i,j;
  double c;
  for(i=0;i<100;i+=2){
    for(j=0;j<100;j+=2){
      c=calc(i,j) //i,jを使ったなんかの計算
      c=calc(i+1,j) //i,jを使ったなんかの計算
      c=calc(i,j+1) //i,jを使ったなんかの計算
      c=calc(i+1,j+1) //i,jを使ったなんかの計算
  }}
}

このように,ループの中での処理を増やすことにより,メモリアクセスの効率化を図り,計算速度の向上を図ることができます.

OpenMPとは

OpenMPとは,複数のCPU(コア)をもつ計算機で有用なライブラリです.最近のPCではデュアルコア以上が普通かと思いますので,そういったPCを所有している場合は特に有効な手法です.Visual Studioでは,プロジェクト→プロパティ→構成プロパティ→C/C++→言語→OpenMPサポートのオプションをはいにするだけで簡単に実行できます.

※Debugモードで利用する場合はC:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugOpenMPからvcomp90d.dllをソリューションディレクトリにコピーする必要があったりします

一番手っ取り早い並列化
#pragma omp parallel
#pragma omp sections
{
  #pragma omp section
  {
  //処理したい式
  }
  #pragma omp section
  {
  //処理したい式
  }
  ...
}

ここに処理したい式をぶち込むといい感じに早くなります.
注意すべきなのは,{}の位置はこのとおりにやらないとダメです.
sectionsやsectionの後ろに{を置くとエラーを食らうことがあります.

さて,ここでアンローリングとOpenMPを組み合わせてみるとこんな感じのサンプルが出来ます.

#include <stdio.h>

int main(void){
  int i,j;
  double c;
  for(i=0;i<100;i+=2){
    for(j=0;j<100;j+=2){
#pragma omp parallel
#pragma omp sections
{
  #pragma omp section
  {
      c=calc(i,j) //i,jを使ったなんかの計算
  }
  #pragma omp section
  {
      c=calc(i+1,j) //i,jを使ったなんかの計算
  }
  #pragma omp section
  {
      c=calc(i,j+1) //i,jを使ったなんかの計算
  }
  #pragma omp section
  {
      c=calc(i+1,j+1) //i,jを使ったなんかの計算
  }
  }}
}
}


これで自分のPCでは20%ほど体感速度が上がりました.
もし時間のかかる処理を大量にやられる機会があれば,是非お試しください.