0

假设我有一个 Fortran 程序,它在一个数组上执行两个任务:任务 A 计算它的平均值,任务 B 将它加倍。关键是任务 B 应该独立于任务 A。当使用 OpenACC 加速程序时,通过使任务 A 异步来同时运行两个任务是有意义的:

program test
    implicit none
    integer, parameter :: n = 1000000
    real(8) :: mean
    real(8) :: array(n)
    real(8) :: array_d(n)

    ! initialize array
    array = [(i, i=1, n)]

    !$acc kernels async num_gangs(1)
    ! Task A: get mean of array
    mean = 0d0
    !$acc loop independent reduction(+:mean)
    do i = 1, n
        mean = mean + array(i)
    end do
    mean = mean / n
    !$acc end kernels

    !$acc kernels
    ! Task B: work on array
    !$acc loop independent
    do i = 1, n
        array(i) = array(i) * 2
    end do
    !$acc end kernels

    !$acc wait
    !$acc end data

    ! print array and mean
    print "(10(g0.2, x))", array(:10)
    print "('mean = ', g0.2)", mean
end program

但是,同时运行两个任务时,任务B会修改任务A正在读取的数组,导致值不正确。在 CPU 上(无加速)我得到:

2.0 4.0 6.0 8.0 10. 12. 14. 16. 18. 20.
mean = 500000.5000000000

在 GPU(使用 NVIDIA HPC SDK)上,我得到一个不同的平均值,这显然是不正确的:

2.0 4.0 6.0 8.0 10. 12. 14. 16. 18. 20.
mean = 999967.6836640000

是否有一种优雅的方式来“保护”任务 A 正在工作的阵列?

4

0 回答 0