2017-12-21 20 views
3

モデルのデータを保持し、そのデータに対していくつかの関数を実行するModelクラスがあります。詳細はおそらくそれほど重要ではないが、以下のデザインを有する。` - >`のループ依存依存は並列化を防ぎます

  • 変数はクラス名前空間に格納される。
  • 変数は、クラスのメソッドのいずれかによって初期化され、解放されます。
  • 変数は他のいくつかの方法で使用されます。次のようにクラスの

A MWEが表示されます。

#include <cstdlib> 


class Model { 
private: 
    int width; 
    int height; 
    int size; 

    int nshift[8];  //Offset from a focal cell's index to its neighbours 
    double *restrict h; //Digital elevation model (height) 
    int *restrict rec; //Index of receiving cell 

    const int NO_FLOW = -1; 
    const double SQRT2 = 1.414213562373095048801688724209698078569671875376948; 
    const double dr[8] = {1,SQRT2,1,SQRT2,1,SQRT2,1,SQRT2}; 

private: 
    void GenerateRandomTerrain(){ 
    //srand(std::random_device()()); 
    for(int y=0;y<height;y++) 
    for(int x=0;x<width;x++){ 
     const int c = y*width+x; 
     h[c] = rand()/(double)RAND_MAX; 
    } 
    } 


public: 
    Model(const int width0, const int height0) 
    : nshift{-1,-width0-1,-width0,-width0+1,1,width0+1,width0,width0-1} 
    { 
    width = width0; 
    height = height0; 
    size = width*height; 

    h  = new double[size]; 

    GenerateRandomTerrain(); 
    } 

    ~Model(){ 
    delete[] h; 
    } 

private: 
    void FindDownstream(){ 
    //! computing receiver array 
    #pragma acc parallel loop collapse(2) independent present(h,rec,width,height) 
    for(int y=2;y<height-2;y++) 
    for(int x=2;x<width-2;x++){ 
     const int c  = y*width+x; 

     //The slope must be greater than zero for there to be downhill flow; 
     //otherwise, the cell is marekd NO_FLOW 
     double max_slope = 0; 
     int max_n  = NO_FLOW; 

     #pragma acc loop seq 
     for(int n=0;n<8;n++){ 
     double slope = (h[c] - h[c+nshift[n]])/dr[n]; 
     if(slope>max_slope){ 
      max_slope = slope; 
      max_n  = n; 
     } 
     } 
     rec[c] = max_n; 
    }  
    } 

public: 
    void run(const int nstep){ 
    rec = new int[size]; 

    #pragma acc enter data copyin(h[0:size],nshift[0:8],height,width,this) create(rec[0:size]) 

    for(int step=0;step<=nstep;step++) 
     FindDownstream(); 

    #pragma acc exit data copyout(h[0:size]) delete(this,rec) 

    delete[] rec; 
    } 

}; 

int main(int argc, char **argv){ 
    Model model(300,300); 
    model.run(100); 

    return 0; 
} 

私が使用してコンパイル:

pgc++ -acc -ta=tesla,pinned,cc60 -Minfo=accel -fast test.cpp -std=c++11 

私は、取得するには、次の警告:一部の掘り

51, Loop without integer trip count will be executed in sequential mode 
    Complex loop carried dependence of rec->,nshift prevents parallelization 
    Loop carried dependence of rec-> prevents parallelization 
    Loop carried backward dependence of rec-> prevents vectorization 

インターネットは、これの典型的な原因がpointeの可能性であることを明らかにする依存関係を引き起こすエイリアシング。

私は*restrictindependent(ここに示す)を使用して、コンパイラにすべて正しいものを伝えようとしましたが、私を無視してループを並列化しません。

restrictを適切に使用して関数に引数としてポインタを渡すと、エラーはなくなりますが、私はこのデザインに対して美的な好みがあります。あるいは、本質的にカーネルであるすべてのメソッドは、関数run()で一緒につなぐことができますが、これも望ましくありません。

私は内側のループにindependentを使用している場合は、私が手:

:/タイル張りの

PGCC-W-0155-内側のループは、ループの入れ子は、別のループディレクティブ(227 actual_code.cpp)を持つべきではない崩壊

しかし、ループは並列化されているように見えます。

PGI 17.9でコンパイルしています。

答えて

1

"height"と "width"はクラスデータのメンバーです。したがって、コンパイラは、外部参照を持つ可能性があると仮定して、これらのループの実行中に値を変更する可能性があります。

解決策は、値をローカル変数にコピーし、ローカル変数をループ境界として使用することです。

外部ループに「折りたたみ(2)」があるので、「独立」句は両方のループに既に適用されています。 (ただし、「独立」は「並列」計算領域のデフォルトですので不要です)。複数のループを折りたたむときは、2番目の「ループ」構造は使用できません。

% cat test.cpp 
#include <cstdlib> 


class Model { 
private: 
    int width; 
    int height; 
    int size; 

    int nshift[8];  //Offset from a focal cell's index to its neighbours 
    double *restrict h; //Digital elevation model (height) 
    int *restrict rec; //Index of receiving cell 

    const int NO_FLOW = -1; 
    const double SQRT2 = 1.414213562373095048801688724209698078569671875376948; 
    const double dr[8] = {1,SQRT2,1,SQRT2,1,SQRT2,1,SQRT2}; 

private: 
    void GenerateRandomTerrain(){ 
    //srand(std::random_device()()); 
    for(int y=0;y<height;y++) 
    for(int x=0;x<width;x++){ 
     const int c = y*width+x; 
     h[c] = rand()/(double)RAND_MAX; 
    } 
    } 


public: 
    Model(const int width0, const int height0) : nshift{-1,-width0-1,-width0,-width0+1,1,width0+1,width0,width0-1} 
    { 
    width = width0; 
    height = height0; 
    size = width*height; 

    h  = new double[size]; 

    GenerateRandomTerrain(); 
    } 

    ~Model(){ 
    delete[] h; 
    } 

private: 
    void FindDownstream(){ 
    //! computing receiver array 
    int hgt = height; 
    int wdt = width; 
    #pragma acc parallel loop collapse(2) present(h,rec) 
    for(int y=2;y<hgt-2;y++) 
    for(int x=2;x<wdt-2;x++){ 
     const int c  = y*wdt+x; 

     //The slope must be greater than zero for there to be downhill flow; 
     //otherwise, the cell is marekd NO_FLOW 
     double max_slope = 0; 
     int max_n  = NO_FLOW; 

     #pragma acc loop seq 
     for(int n=0;n<8;n++){ 
     double slope = (h[c] - h[c+nshift[n]])/dr[n]; 
     if(slope>max_slope){ 
      max_slope = slope; 
      max_n  = n; 
     } 
     } 
     rec[c] = max_n; 
    } 
    } 

public: 
    void run(const int nstep){ 
    rec = new int[size]; 

    #pragma acc enter data copyin(this,h[0:size],nshift[0:8]) create(rec[0:size]) 

    for(int step=0;step<=nstep;step++) 
     FindDownstream(); 

    #pragma acc exit data copyout(h[0:size]) delete(rec,nshift,this) 

    delete[] rec; 
    } 

}; 

int main(int argc, char **argv){ 
    Model model(300,300); 
    model.run(100); 

    return 0; 
} 
% pgc++ test.cpp -w --c++11 -Minfo=accel -ta=tesla:cc60 -V17.10; a.out 
Model::FindDownstream(): 
    49, Generating present(h[:]) 
     Accelerator kernel generated 
     Generating Tesla code 
     51, #pragma acc loop gang, vector(128) collapse(2) /* blockIdx.x threadIdx.x */ 
     52, /* blockIdx.x threadIdx.x collapsed */ 
     61, #pragma acc loop seq 
    49, Generating implicit copy(this[:]) 
     Generating present(rec[:]) 
    61, Loop carried scalar dependence for max_slope at line 63 
Model::run(int): 
    74, Generating enter data copyin(nshift[:],h[:size]) 
     Generating enter data create(rec[:size]) 
     Generating enter data copyin(this[:1]) 
    83, Generating exit data delete(this[:1],rec[:1]) 
     Generating exit data copyout(h[:size]) 
     Generating exit data delete(nshift[:]) 
+0

ありがとう、マット!それは意味をなさないが、それは確かに私がコンパイラの出力から取り除いたものではない: 'rec - >、nshift 'の言及は修正が必要な問題のように思えた。もしコンパイラが 'height'と' width'が揮発性であるかもしれないと思っているのであれば、コンパイラが何らかの形でそれを識別できれば涼しいでしょう。 – Richard

+0

主なメッセージは、高さと幅が揮発性であるためにカウントできないループに関するものです。 "rec->"依存性は、計算されたインデックスの使用によって引き起こされます。あなたは "並列ループ"を使用しているので、コンパイラは依存関係を無視します。 –

関連する問題