2016-08-10 14 views
1

私は当初は並列計算用に設計されていなかった非常に長いプログラムをスピードアップしようとしています。したがって私はgfortranで自動並列化を試しています。gfortranとの自動並列化

私は基本的には、いくつかのループを実行し、実行時間を計測していることを、次のテストプログラムを持っている:

program autoparallel 

    implicit none 

    integer      :: N = 10000 
    double precision, allocatable :: A(:, :), X(:), Y(:) 

    integer      :: i, j 
    integer      :: time_start, time_finish, time_rate 

    call system_clock (time_start, time_rate) 

    allocate(A(N, N), X(N), Y(N)) 

    do i=1, N 
     do j=1, N 
      A(i, j) = i * j 
     end do 
    end do 

    do i=1, N 
     X(i) = i 
    end do 

    do i=1, N 
     Y(i) = 0.d0 
    end do 

    do i=1, N 
     do j=1, N 
      Y(i) = Y(i) + A(j, i) * X(j) 
     end do 
    end do 

    call system_clock (time_finish, time_rate) 

    write(*,*) 'Elapsed time: ', (time_finish-time_start)/real(time_rate), ' seconds' 

    write(*,*) Y(1), Y(N) 

    deallocate(A, X, Y) 

end program autoparallel 

私は別のコンパイラフラグで5回ずつ、それを実行:だから

gfortran test.f90 
4.14799976  seconds 
4.51900005  seconds 
4.42399979  seconds 
4.15600014  seconds 
4.38000011  seconds 

gfortran -floop-parallelize-all -ftree-parallelize-loops=2 autoparallel.f90 
4.36899996  seconds 
4.07499981  seconds 
4.35599995  seconds 
4.17899990  seconds 
4.37500000  seconds 

gfortran -floop-parallelize-all -ftree-parallelize-loops=4 autoparallel.f90 
4.28399992  seconds 
4.42600012  seconds 
4.19999981  seconds 
4.33199978  seconds 
4.14499998  seconds 

gfortran -O3 autoparallel.f90 
3.63599992  seconds 
3.63599992  seconds 
3.79800010  seconds 
3.55900002  seconds 
3.59599996  seconds 

gfortran -O3 -floop-parallelize-all -ftree-parallelize-loops=4 autoparallel.f90 
3.09299994  seconds 
3.08299994  seconds 
3.46799994  seconds 
3.00099993  seconds 
3.00699997  seconds 

gfortran -O3 -floop-nest-optimize autoparallel.f90 
1.03100002  seconds 
1.01800001  seconds 
1.02300000  seconds 
1.03600001  seconds 
0.947000027  seconds 

を基本的に実行時間はスレッドの数と平らです。最適化の後でのみ、自動並列化が開始されます。 これがなぜか理解しようとしています。

少なくともすべてのi -loopsは、最適化を行わずに複数のスレッドに分散させることができます。

ここでは正確に何が起こっていますか?そして、私はプログラムをさらに高速化するために使用できる他のコンパイラフラグがありますか?そして、どのフラグが私の並列化の目標と矛盾しているでしょうか?

-floop-nest-optimizeは、-floop-parallelize-allと一緒には使用できません。 エラー:

isl_constraint.c:497: position out of bounds 
+1

スマート最適化コンパイラので、したがって、それは '定義ループを気にする必要はありません、何もY' 'の値で行われていないことを理解するであろう(とはかなりスマートすることができ、コンパイラの最適化) Y 'である。同様に、「X」と「A」の定義を気にする必要がないことを認識します。そうすれば、プログラム全体がいくつかのタイマークエリといくつかの出力ステートメントに崩壊するでしょう。私はgfortranがこれを行うかどうかを調査していませんが(時間はそうではないと示唆しています)、最適化を有効にすると、あなたが思うものを実行していない可能性があります。 – IanH

+0

最初のループはループネスト切り替えの明白な候補ですが、私はそれを自動的に見つけるためにgfortranを考慮しません。また、gfortranが最後のもので自動的にdot_productの置換を実行することも期待していません。 – tim18

+1

deallocate()の前に "print *、Y(1)、Y(N)"を置くと、デッドコードの削除の可能性を避けることができます。 osx10.9でgfort-6.1を使用した場合、-floop-nest-optimizeを付けることで計算がほぼ2倍速くなりました@(これらの並列(?)オプションはわかりませんでしたので非常に面白いです...) – roygvib

答えて

0

は私がその第3のループは、通常のOpenMP REDUCTION(!またはのifortでDIR $ DO SIMD減)と改善されていることがわかります。

USE OMPLIB 
.... 
do i=1, N 
    !$OMP DO SIMD REDUCTION(+:Y) 
    do j=1, N 
     Y(i) = Y(i) + A(j, i) * X(j) 
    end do 
end do 

おそらく、Yループ(I)は、Iループと並行するようにプライベートにすることができます。作業負荷が高い場合を除き、これらの単純なケースではIループを並列化するほどの改善はほとんどありません。

YRMV

+0

OpenMPディレクティブはもちろん、コードの多くの場所に追加できます。問題は、自動スレッド化とスレッド数でうまく拡張できない理由です。SIMDディレクティブはベースコードの速度を上げることができますが、スケーリングを治すことはできません。それは実際にそれを傷つけるかもしれません(より速いコードはもっと速くするのが難しいです)。 –

+0

これはネストの最適化を妨げる可能性があることに注意してください。 –

+0

@Vladimir「ツアーオペレーション」とは何ですか? SIMDのポイントは、これは検査によって、ベクトル最適化に適しているということです。並行最適化ではそうではありません。たいていの場合、どこでどのように速度を上げるかを決定するために何らかの努力が必要です。 – Holmz