0

私は、OpenACC を使用してかなり大きなサイズのコードを計測している最中です。現在、次のように、他のいくつかのルーチン bar、far、および boo を呼び出すルーチン foo を遅延させています。

subroutine foo

real x(100,25),y(100,25),z(100,25)
real barout(25), farout(25), booout(25)

do i=1,25
  call bar(barout, x(1,i),y(1,i),z(1,i))
  call far(farout, x(1,i),y(1,i),z(1,i))
  call boo(booout, x(1,i),y(1,i),z(1,i))
enddo

....

end subroutine foo

ポイントのカップル: 1) x、y、および z は、ループを通じて一定のままです。2) ここにあるコードの構造が気に入らないかもしれませんが、それは私の仕事の説明を超えています。私は OpenACC で計測することになっています。

私は現在、「bar」への呼び出しに集中しています。bar をベクトルルーチンにしたい。私は far と boo に対して同じことをする準備ができていません。したがって、並列領域内から bar を呼び出したいのですが、far と boo で同じことを行う準備ができていません。(これは進行中の作業だと言いましたよね?)今、できると思います!-- バーを独自の並列領域に挟み、各ループ反復でバーとの間でデータをコピーします

!$acc data copy(barout) &
!$acc&     copyin(x(:,:),y(:,:),z(:,:))
!$acc parallel
call bar( .... )
!$acc en parallel
!$acc end data

しかし、それは大量のデータ転送です。x、y、z を 1 回だけデバイスに転送できればよいのですが。各ルーチンには独自のデータ領域があるため、私が理解しているように (間違っていたら訂正してください!)、ループ全体を 1 つのデータ領域に入れることはできません。ここに私が試した代替案があります

subroutine foo
!$acc routine(bar) vector

real x(100,25),y(100,25),z(100,25)
real barout(25), farout(25), booout(25)

!$acc data create(x(:,:),y(:,:),z(:,:))
!$acc end data
do i=1,25
!$acc data copy(barout(:)) &
!$acc&     present(x(:,:),y(:,:),z(:,:))
!$acc parallel
  call bar(barout, x(1,i),y(1,i),z(1,i))
!$acc end parallel
!$acc end data
  call far(farout, x(1,i),y(1,i),z(1,i))
  call boo(booout, x(1,i),y(1,i),z(1,i))
enddo

....

end subroutine foo

ただし、 のデータがcopyinデバイス上に保持されないため、これは機能しません。data present句が現れると消えます。(私も試しdata createましたdata copyin。)

私がここでやろうとしていることをする方法はありますか?ありがとう。

4

1 に答える 1

2

外側のデータ領域が "i" ループ全体にまたがるようにします。あなたが持っているように、開始の直後に「終了データ」があるため、x、y、および z は「i」ループの前に削除され、存在しません。また、ループ内で update 句を使用してデータ転送を管理することもお勧めします。何かのようなもの:

subroutine foo
!$acc routine(bar) vector

real x(100,25),y(100,25),z(100,25)
real barout(25), farout(25), booout(25)

!$acc data copyin(x, y, z), create(barout)
do i=1,25
!$acc update device(barout)
!$acc parallel
  call bar(barout, x(1,i),y(1,i),z(1,i))
!$acc end parallel
!$acc update host(barout)
  call far(farout, x(1,i),y(1,i),z(1,i))
  call boo(booout, x(1,i),y(1,i),z(1,i))
enddo
!$end data
....

end subroutine foo

ノート:

「bar」はベクトル ルーチンであるため、「並列」領域から呼び出すことは、1 つのギャングのみを使用することを意味します。間違ったコードではありませんが、パフォーマンスが低下します。ホストルーチンのままにして、「並列」を「バー」の中に入れて、「ギャング」と「ベクトル」の両方を使用できるようにする方がよいかもしれません。確かに、後で内側の「並列」領域を「i」ループの周りの「並列ループ ギャング」に移動することが目的である場合は、そのままにしておくのが理にかなっています。

これらの変数がどこで初期化されるかわからなかったので、コードを x、y、および z にコピーするように変更しました。それらが「bar」で初期化されている場合は、「create」を使用するようにこれらを元に戻すことができますが、更新ディレクティブを追加して、ホストとデバイスのコピーを同期させます。

于 2016-02-25T22:07:48.257 に答える