【发布时间】:2016-08-10 20:58:12
【问题描述】:
我正在尝试加速一个原本不是为并行计算设计的相当冗长的程序。因此,我正在尝试使用 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
我用不同的编译器标志执行了五次:
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
【问题讨论】:
-
一个聪明的优化编译器(优化编译器可能非常聪明)会意识到
Y的值没有做任何事情,因此它不需要为定义@的循环而烦恼987654329@。同样,它会意识到它不需要费心定义X和A。这会将整个程序折叠成一些计时器查询和一些输出语句。我还没有调查 gfortran 是否这样做(时代建议不会),但启用优化后,您可能不会执行您认为的操作。 -
第一个循环显然是循环嵌套切换的候选者,但我不指望 gfortran 会自动找到它。我也不指望 gfortran 在最后一个执行自动 dot_product 替换。
-
在 deallocate() 之前放置 "print *, Y(1), Y(N)" 可能有助于避免可能的死代码消除。在 osx10.9 上使用 gfort-6.1,附加 -floop-nest-optimize 使计算速度几乎快了两倍 @@(我不知道这些并行 (?) 选项非常有趣......)
-
这很好。我编辑了原始帖子。
-floop-nest-optimize不能与自动并行一起使用。 -
并行化不会很好地扩展,因为您的操作是内存带宽有限的,不受 CPU 速度的限制。
标签: parallel-processing fortran gfortran