Вызов Fortran OpenACC из файла CUDA. Как скомпилировать с PGI?

У меня есть код CUDA, в который я хотел бы включить внешний код, состоящий из Fortran с ядрами OpenACC. У меня есть два файла со следующим содержанием, вдохновленным обсуждением на веб-сайте NVIDIA. Файл main.cu следующий:

#include <cstdio>

extern "C" void saxpy(int*, float*, float*, float*);

int main(int argc, char **argv)
{
    float* x;
    float* y;
    float* dx;
    float* dy;

    int n = 1<<20;

    x = (float*) malloc(n*sizeof(float));
    y = (float*) malloc(n*sizeof(float));

    for (int i=0; i<n; ++i)
    {
        x[i] = 1.f;
        y[i] = 0.f;
    }

    cudaMalloc((void**) &dx, (size_t) n*sizeof(float));
    cudaMalloc((void**) &dy, (size_t) n*sizeof(float));

    cudaMemcpy(dx, x, (size_t) n*sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(dy, y, (size_t) n*sizeof(float), cudaMemcpyHostToDevice);

    float factor = 2.f;
    saxpy(&n, &factor, dx, dy);

    cudaMemcpy(y, dy, (size_t) n*sizeof(float), cudaMemcpyDeviceToHost);
    printf("%f, %f\n", y[0], y[n-1]);

    return 0;
}

Второй файл saxpy.f90:

subroutine saxpy(n, a, x, y) bind(c, name="saxpy")
    use iso_c_binding, only: c_int, c_float

    integer(kind=c_int), intent(in) :: n
    real(kind=c_float), intent(in) :: a
    real(kind=c_float), dimension(n), intent(in) :: x(n)
    real(kind=c_float), dimension(n), intent(inout) :: y(n)

    !$acc parallel deviceptr(x, y)
    do i = 1, n
        y(i) = y(i) + a*x(i)
    end do
    !$acc end parallel
end subroutine

Как мне скомпилировать это с nvcc и компилятором PGI вместе? Я пробовал много разных вариантов, но всегда останавливался на неразрешенных внешних факторах.

Я пробовал: pgf90 -ta=tesla:cc35 -acc saxpy.f90 -c для файла Fortran, и он отлично компилируется. Следующий шаг - вот где я застрял. Это: nvcc -arch=sm_35 -ccbin pgc++ main.cu saxpy.o дает неразрешенные внешние факторы, для которых я не знаю, как их решить. Как узнать, какие внешние библиотеки включить?


person Chiel    schedule 30.03.2020    source источник
comment
Попытка использовать pgc ++ в качестве компилятора не поддерживается. Вероятно, вам понадобится что-то вроде этого: stackoverflow.com/a/38214143/681865, хотя я не могу ничего тестировать прямо сейчас   -  person talonmies    schedule 30.03.2020
comment
@talonmies. Как это поможет мне в компиляции кода устройства cuda? Мне нужно поместить это в отдельный файл?   -  person Chiel    schedule 30.03.2020
comment
Вызов pgf90 в вашем вопросе уже компилирует код устройства. Вам просто нужно отключить отдельную компиляцию устройства (как показано в связанном ответе). Вам нужно будет решить, какие библиотеки PGI вам нужно связать, используя nvcc самостоятельно.   -  person talonmies    schedule 30.03.2020
comment
@talonmies. Но как насчет распределения памяти и копий между хостом и графическим процессором?   -  person Chiel    schedule 30.03.2020
comment
Что насчет них? Они находятся в файле .cu, который будет скомпилирован nvcc и предоставлен библиотекой API времени выполнения cuda, которую необходимо связать.   -  person talonmies    schedule 30.03.2020


Ответы (1)


Скорее всего, символы отсутствуют, поскольку вы не добавляете в свою ссылку библиотеки времени выполнения OpenACC или Fortran. Кроме того, если для связывания не используется драйвер PGI, вам необходимо добавить флаг «nordc». Например:

% pgfortran -c -ta=tesla:cc70,nordc saxpy.f90                                       
% nvcc -arch=sm_70 -ccbin pgc++ -Xcompiler "-ta=tesla:cc70 -pgf90libs" main.cu saxpy.o
% a.out
2.000000, 2.000000

Хотя я бы рекомендовал использовать pgfortran для компоновки, чтобы вы могли использовать RDC и не добавляли библиотеки времени выполнения Fortran:

% nvcc -arch=sm_70 -ccbin pgc++ -c main.cu
% pgfortran -Mcuda -ta=tesla:cc70 -Mnomain saxpy.f90 main.o
saxpy.f90:
% a.out
2.000000, 2.000000
person Mat Colgrove    schedule 30.03.2020
comment
Большой. Это хорошо работает. Мне нужно было добавить -lstd++ к вызову pgfortran для компиляции. - person Chiel; 30.03.2020
comment
Я привел еще несколько подобных примеров взаимодействия, которые могут вам пригодиться. Теперь мне нужно вернуться и убедиться, что им не нужен -lstd ++ с недавними компиляторами. github.com/jefflarkin/openacc-interoperability - person jefflarkin; 31.03.2020
comment
Джефф, есть также флаг pgfortran -c ++ libs, который заставит драйвер добавить библиотеки C ++ в ссылку. - person Mat Colgrove; 31.03.2020
comment
@jefflarkin Это действительно полезно. Я использовал компилятор PGI18, так как он совместим с CUDA10 на суперкомпьютере, который я использую. - person Chiel; 01.04.2020