Матмуль в цикле OpenACC Fortran

Ускорение кода Fortran с помощью OpenACC с использованием компилятора PGI, у меня возникли проблемы с вызовом matmul в ускоренном цикле.

В упрощенном примере я применяю единичную матрицу к двум векторам, поэтому входные и выходные значения должны быть одинаковыми:

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

        a = reshape([1, 0, 0, 0, 1, 0, 0, 0, 1], [3, 3])
        v1 = reshape([1, 2, 3, 4, 5, 6], [3, 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(:,:),v1(:,:)) [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

вторая строка должна быть такой же, как и первая, что имеет место при последовательном выполнении. Что не так в коде?


person Neraste    schedule 20.01.2021    source источник
comment
похоже, что оба потока загрузили второй столбец v1   -  person Giogre    schedule 20.01.2021


Ответы (2)


Похоже, проблема компилятора. Проблема в следующем:

Generating implicit copyout(z_a_0(:)) 

z_a_0 - это временный массив компилятора, который создается для хранения промежуточного результата вызова matmul. Его объявление выводится из цикла, а затем копируется обратно как общий массив. Поскольку он разделяется, он вызывает состояние гонки.

Я отправил отчет о проблеме (TPR № 29482) и отправил его нашим инженерам для дальнейшего изучения.

person Mat Colgrove    schedule 20.01.2021

@Mat Colgrove объяснил причину неправильного поведения. Обходной путь, который я нашел, заключался в том, чтобы явно написать матричное умножение векторов:

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

        a = reshape([1, 0, 0, 0, 1, 0, 0, 0, 1], [3, 3])
        v1 = reshape([1, 2, 3, 4, 5, 6], [3, 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
person Neraste    schedule 21.01.2021