【问题标题】:Automatic parallelization with gfortran使用 gfortran 自动并行化
【发布时间】: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@。同样,它会意识到它不需要费心定义XA。这会将整个程序折叠成一些计时器查询和一些输出语句。我还没有调查 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


【解决方案1】:

我发现通常使用 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

【讨论】:

  • 当然可以在代码的很多地方添加OpenMP指令。问题是关于自动线程以及为什么它不能很好地随着线程数量而扩展。 SIMD 指令可以加快基本代码的速度,但我怀疑它是否能解决缩放问题。它实际上可能会伤害它(更快的代码更难变得更快。)
  • 请注意,这可能会阻止嵌套优化。
  • @Vladimir 什么是“巡回演出”? SIMD 的要点是,通过检查,这对向量优化很有好处……而对于并行优化来说则不然。大多数情况下,要确定在何处以及如何加快速度需要付出一些努力。
  • "tour your" 注意问题是关于自动并行化的。不是如何手动优化给定的简化代码示例。
  • 是的......我会在循环完成所有工作之前将第一个时钟向下移动。分配和归零数组或初始化它们的时间可能会影响对工作时间的更精确测量。
猜你喜欢
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 2019-05-19
相关资源
最近更新 更多