OpenACC Fortran 循环中的 Matmul

问题描述

使用 PGI 编译器通过 OpenACC 加速 Fortran 代码,我在加速循环中遇到 matmul 调用问题。

在简化示例中,我将单位矩阵应用于两个向量,因此输入和输出值应该相同:

program test
        implicit none
        integer :: a(3,3)
        integer :: v1(3,2),v2(3,2)
        integer :: i

        a = reshape([1,1,1],[3,3])
        v1 = reshape([1,2,3,4,5,6],2])

        print *,v1

        !$acc kernels copyin(a,v1) copyout(v2)
        !$acc loop independent
        do i = 1,2
                v2(:,i) = matmul(a,v1(:,i))
        enddo
        !$acc end kernels

        print *,v2
endprogram

在使用 PGI 编译器 20.9 版进行编译时,我得到了以下信息:

test:
     12,Generating copyin(a(:,:),:)) [if not already present]
         Generating implicit copyout(z_a_0(:)) [if not already present]
         Generating copyout(v2(:,:)) [if not already present]
     14,Loop is parallelizable
         Generating Tesla code
         14,!$acc loop gang ! blockidx%x
         15,!$acc loop vector(32) ! threadidx%x
     15,Loop is parallelizable

运行代码给出以下值:

1 2 3 4 5 6
4 5 6 4 5 6

第二行应该和第一行一样,顺序执行就是这种情况。代码有什么问题?

解决方法

看起来是编译器问题。问题线是:

Generating implicit copyout(z_a_0(:)) 

"z_a_0" 是正在创建的编译器临时数组,用于保存调用 matmul 的中间结果。它的声明被提升出循环,然后作为共享数组复制回。由于它是共享的,因此会导致竞争条件。

我已提交问题报告 (TPR #29482) 并将其发送给我们的工程师进行进一步调查。

,

@Mat Colgrove 解释了错误行为的原因。我发现的解决方法是明确地编写矩阵向量乘法:

program test
        implicit none
        integer :: a(3,3)
        integer :: v1(3,2),v2(3,2)
        integer :: i,j,k

        a = reshape([1,1,1],[3,3])
        v1 = reshape([1,2,3,4,5,6],2])

        print *,v1

        !$acc kernels copyin(a,v1) copyout(v2)
        !$acc loop independent
        do i = 1,2
                !$acc loop seq
                do k = 1,3
                        v2(k,i) = 0
                        !$acc loop seq
                        do j = 1,3
                                v2(k,i) = v2(k,i) + a(j,k) * v1(j,i)
                        enddo
                enddo
        enddo
        !$acc end kernels

        print *,v2
endprogram