OpenA CC: Как выбрать массив на устройстве из указателя на соответствующий массив на хосте - PullRequest
0 голосов
/ 07 января 2020

Я пытаюсь разгрузить существующий код C в графический процессор, используя OpenA CC. В исходном коде ЦП много раз требуется выбирать массив данных на основе значения какого-либо параметра. Пример кода ЦП приведен ниже:

#include <stdio.h>
#include <stdlib.h>


void selectArray (int **F, int a);

#define NN 1000
int *C, *D, *E;

int main(void)
{
    int *F, a = 10; // a is the parameter used to select the array

    C = (int *)malloc(NN * sizeof(int));
    D = (int *)malloc(NN * sizeof(int));
    E = (int *)malloc(NN * sizeof(int));

    for (int i = 0; i < NN; i++)
    {
        C[i] = 10;
        D[i] = 20;
    }

    selectArray(&F, a);

    for (int i = 0; i < NN; i++)
    {
       E[i] = 2 * F[i];
    }

    for (int i = 0; i < 200; i++)
       printf("%d %d \n", i, E[i]);

    return 0;

}

void selectArray(int **F, int a)
{
    if (a <= 15)
    {
        (*F) = C;
    }
    else
    {
        (*F) = D;
    }
}

Для версии кода OpenA CC массивы C и D уже присутствуют в графическом процессоре, и необходимо выполнить дальнейшие вычисления для массива, выбранного на основа параметра a .

#include <stdio.h>
#include <stdlib.h>

void selectArray(int **F, int a);

#define NN 1000
int *C, *D, *E;

int main(void)
{
    int *F, a = 10; // a is the parameter used to select the array

    C = (int *)malloc(NN * sizeof(int));
    D = (int *)malloc(NN * sizeof(int));
    E = (int *)malloc(NN * sizeof(int));

#pragma acc enter data create(C[:NN], D[:NN])
#pragma acc parallel loop present(C[:NN], D[:NN])
    for (int i = 0; i < NN; i++)
    {
        C[i] = 10;
        D[i] = 20;
    }

    selectArray(&F, a);

#pragma acc enter data copyin(F[:1]) create(E[:NN])

// Here, I cannot figure out how to point F to a selected array (C or D) on the device

#pragma acc parallel loop
        for (int i = 0; i < NN; i++)
        {
            E[i] = 2 * F[i]; //further calculations on selected array on GPU
        }
    }

#pragma acc exit data delete (C[:NN], D[:NN], F)copyout(E[:200])
    for (int i = 0; i < 200; i++)
        printf("%d %d \n", i, E[i]);

    return 0;
}

void selectArray(int **F, int a)
{
    if (a <= 15)
    {
        (*F) = C;
    }
    else
    {
        (*F) = D;
    }
}

В реальном коде массивы C и D рассчитываются в разных функциях, а не в основной функции. Я попытался найти inte rnet, чтобы решить эту проблему, но я не смог найти связанный пример. Я использую компилятор PGI 19.10 на Windows 10. Требуется помощь в этом отношении. Заранее спасибо

1 Ответ

1 голос
/ 08 января 2020

Вам просто нужно добавить «present (F)» на параллель l oop и не включать «F» в область данных. Поскольку поиск таблицы cc выполняется по адресу хоста, если «F» совпадает с существующим адресом хоста, присутствующим на устройстве, он будет ассоциировать «F» с тем же адресом устройства. Тем не менее, не помещайте «F» в его собственную область данных и, в частности, не удаляйте его, так как это вызовет несколько освобождений на одном массиве устройств.

Я немного изменил ваш код, так что «F» указывает на «C» в одном случае и «D» во втором.

% cat test.c
#include <stdio.h>
#include <stdlib.h>

void selectArray(int **F, int a);

#define NN 1000
int *C, *D, *E;

int main(void)
{
    int *F, a = 10; // a is the parameter used to select the array

    C = (int *)malloc(NN * sizeof(int));
    D = (int *)malloc(NN * sizeof(int));
    E = (int *)malloc(NN * sizeof(int));

#pragma acc enter data create(C[:NN], D[:NN], E[:NN])
#pragma acc parallel loop present(C[:NN], D[:NN])
    for (int i = 0; i < NN; i++)
    {
        C[i] = 10;
        D[i] = 20;
    }

    for (a=10;a<=20;a+=10) {
       selectArray(&F, a);

#pragma acc parallel loop present(E,F)
       for (int i = 0; i < NN; i++)
       {
          E[i] = 2 * F[i]; //further calculations on selected array on GPU
       }
#pragma acc update host(E[:20])
       for (int i = 0; i < 20; i++)
       {
          printf("a=%d E[%d]=%d \n", a, i, E[i]);
       }
     }
#pragma acc exit data delete(C, D, E)
    return 0;
}

void selectArray(int **F, int a)
{
    if (a <= 15)
    {
        (*F) = C;
    }
    else
    {
        (*F) = D;
    }
}
% pgcc -ta=tesla -Minfo=accel test.c; a.out
main:
     17, Generating enter data create(D[:1000],E[:1000],C[:1000])
     18, Generating present(D[:1000],C[:1000])
         Generating Tesla code
         19, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
     28, Generating present(E[:],F[:])
         Generating Tesla code
         29, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
     34, Generating update self(E[:20])
     39, Generating exit data delete(E[:1],D[:1],C[:1])
a=10 E[0]=20
a=10 E[1]=20
a=10 E[2]=20
a=10 E[3]=20
a=10 E[4]=20
a=10 E[5]=20
a=10 E[6]=20
a=10 E[7]=20
a=10 E[8]=20
a=10 E[9]=20
a=10 E[10]=20
a=10 E[11]=20
a=10 E[12]=20
a=10 E[13]=20
a=10 E[14]=20
a=10 E[15]=20
a=10 E[16]=20
a=10 E[17]=20
a=10 E[18]=20
a=10 E[19]=20
a=20 E[0]=40
a=20 E[1]=40
a=20 E[2]=40
a=20 E[3]=40
a=20 E[4]=40
a=20 E[5]=40
a=20 E[6]=40
a=20 E[7]=40
a=20 E[8]=40
a=20 E[9]=40
a=20 E[10]=40
a=20 E[11]=40
a=20 E[12]=40
a=20 E[13]=40
a=20 E[14]=40
a=20 E[15]=40
a=20 E[16]=40
a=20 E[17]=40
a=20 E[18]=40
a=20 E[19]=40
...