2016-11-03 11 views
1

インテルのifortコンパイラv16でコンパイルされたFortranコードで簡単なDot Product計算を並列処理する方法を理解しようとしています。以下、より複雑なプロセスのために使用されるプログラムの一部ですが、ほとんどの時間はプログラムで費やされている場所です:ドットプロダクトの並列処理

double precision function ddot(n,dx,incx,dy,incy) 
c 
c  forms the dot product of two vectors. 
c  uses unrolled loops for increments equal to one. 
c  jack dongarra, linpack, 3/11/78. 
c  modified 12/3/93, array(1) declarations changed to array(*) 
c 
     double precision dx(*),dy(*),dtemp 
     integer i,incx,incy,ix,iy,m,mp1,n 
c 
     CALL OMP_SET_NUM_THREADS(12) 
     ddot = 0.0d0 
     dtemp = 0.0d0 
     if(n.le.0)return 
     if(incx.eq.1.and.incy.eq.1)go to 20 
c 
c  code for unequal increments or equal increments 
c   not equal to 1 
c 
     ix = 1 
     iy = 1 
     if(incx.lt.0)ix = (-n+1)*incx + 1 
     if(incy.lt.0)iy = (-n+1)*incy + 1 
     do 10 i = 1,n 
     dtemp = dtemp + dx(ix)*dy(iy) 
     ix = ix + incx 
     iy = iy + incy 
    10 continue 
     ddot = dtemp 
     return 
c 
c  code for both increments equal to 1 
c 
c 
c  clean-up loop 
c 
    20 m = mod(n,5) 
     if(m .eq. 0) go to 40 
!$OMP PARALLEL DO 
!$OMP& DEFAULT(NONE) SHARED(dx,dy,m) PRIVATE(i) 
!$OMP& SCHEDULE(STATIC) 
!$OMP& REDUCTION(+ : dtemp) 
     do 30 i = 1,m 
     dtemp = dtemp + dx(i)*dy(i) 
    30 continue 
!$OMP END PARALLEL DO 
     if(n .lt. 5) go to 60 
    40 mp1 = m + 1 
!$OMP PARALLEL DO 
!$OMP& DEFAULT(NONE) SHARED(dx,dy,n,mp1) PRIVATE(i) 
!$OMP& SCHEDULE(STATIC) 
!$OMP& REDUCTION(+ : dtemp) 
     do 50 i = mp1,n,5 
     dtemp = dtemp + dx(i)*dy(i) + dx(i + 1)*dy(i + 1) + 
    * dx(i + 2)*dy(i + 2) + dx(i + 3)*dy(i + 3) + dx(i + 4)*dy(i + 4) 
    50 continue 
!$OMP END PARALLEL DO 
    60 ddot = dtemp 
     return 
     end 

私はOpenMPのコマンドに新しいですし、私が何かを持っているかなり確信しています面白いところがありますが、全体を単一のコアよりも遅くすることができます。現在私は、遅い4(4)コアマシンで4スレッドで実行しようとしましたが、実際には12スレッドを処理用に指定した大きな20(40)コアマシンよりも少し速くなりました。この時点で私はコードが面白いと思っていて、私が欲しくないことをしています。

Doループの上位レベルも並列化することができますが、ixiyの定義方法はわかりませんでした。

精度は非常に重要なので、コンパイラはfp-modeに正確に設定されています。私はそれがまったく問題なのかどうかはわかりませんが、コードが回答を生成することができれば、正しいと思われます。基本的には、このコードの高速化の方法を理解しようとしていますが、代わりに並列処理では処理が遅くなるようです。

+0

Ufでは、 'CONTINUE'ではなく' END DO'を使うことをお勧めします。本当にコードを読むのは難しいです。 –

+2

Intelは、MKLライブラリのlinpack ddotを高速化するすべての作業を行っています。とりわけ、これはアンロールを5で破棄し、いくつかのターゲットアーキテクチャを最適化することを含む。あなたは、単一スレッドのsimd削減が数千のサイズまで使用されていることが分かります(dot_productは小規模なケースを処理できます)。fp-model preciseは、ユーザーの制御からの精度の改善をわずかには避けるため、最適化された縮小を防ぎます。 – tim18

+0

Intelは通常VIPOと言っています... "vector inner" "parallel outer"。私はそれをすべて「平行do」から「SIMDを行う」に変更します。得られるべきものがあれば、最も外側の部分に平行します。 VIの部分は簡単ですが、キャッシュミスがあれば遅くなります。あなたがifortを持っているなら、あなたはvtuneを持っていますか? – Holmz

答えて

1

多くのインテルWebセミナーがあります。

私はOpenMP SIMD REDUCTIONを実行する開口部最適ヒストグラムコードを持っています。そこで、ベクトルを(大きな、nthreads)配列に持ち込み、各スレッドを並列領域に配置することにしました。一般に、単一のコアを使用するよりも遅く実行されます。 (私はまだvtuneを試していません)

FFTを使った他の類似したアレイ手法がより速く実行され、コアはすべてスケーリングが良好で100%です。

基本的には、問題を解決するか、より効果的なテストが必要です。すべてのOpenMP並列処理は開始に時間がかかります。そのため、最外層ではなく、厳しいレベルで停止する必要があります。

は、一般的に、あなたは、PURE関数またはサブルーチンとしたほうが良い、とそこにもVECTORである(REF(変数))と基準が新しいifort16で

!DEC$ ATTRIBUTES VECTOR ... 

使用することができます。 すべてが歌唱されたら、パラレルを試みることができます。

並列化されたコードを高速化するためには、DO 50には大きな数字が必要です。そうでないと、OpenMPの並列「スタートアップ」があまりにも時間を浪費します。

より速いコード(実際には速度低下のないコード)を得ることについての洞察を与えるために、キャッシュミスなどを見つけるのを助けるためにvtune以外にはたくさんありません。結局のところ、それはgfortranを使ってコンパイルする価値があるかもしれません。私は一般的に、2つのコンパイラを実行すると全体的なコードを改善するための洞察が得られることがわかります。しかし、あなたがDEC $ Extensionsから利益を得るなら、gfortranは役に立たないかもしれません。 CONTIGUOUSは機能を試す価値があります。