2016-07-07 9 views
1

와 PGI OpenACC 지원 라이브러리를 연결 및 GCC로 구축되는 프로그램에 연결 : 이제 c - Linking a PGI OpenACC-enabled library with gccC는 - 동적으로 내가 PGI와 <strong>정적 라이브러리</strong>의 생성에 관한 질문을, 이전 GCC

, 나는 동일한 질문이 있지만 동적으로입니다. 라이브러리가 인데 동적으로이 PGI로 빌드되는 동안 어떻게 gcc로 프로그램을 만들 수 있습니까?

는 또한, 고려 다음과 같은 사실은 :

  • 나는 둘 다 너무 동일한의 OpenMP 프라그 및 루틴을 인식합니다. 예를 들어 라이브러리에서 OpenMP 중요 영역을 사용하면 전체 프로그램이 해당 섹션에서 직렬화되어야합니다.

  • OpenACC pragma는 PGI로 작성된 라이브러리에서 사용됩니다.

  • 내 응용 프로그램에서 라이브러리를 완전히 동적으로로드하십시오. lib를 열 때 dlopen을 사용하고 기능을 찾으려면 dlsym을 사용합니다.

  • 또한 내 스레드가 데이터 전송 및/또는 계산을 위해 GPU에 동시에 액세스 할 수 있기를 바랍니다. 자세한 내용은 다음 코드 스 니펫을 참조하십시오. call to cuMemcpyHtoDAsync returned error 1: Invalid value


    참고 : 다음 코드를 구축 할 때, 내가 의도적으로 대신 PGI의 OpenMP를 라이브러리의 LibGOMP (-lgomp)를 사용 (LIB 및 주요 코드 다음과 같은 예를 구축,

이 오류가 방출 -lpgmp) (예 : lib 및 main).


해방 코드 :

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

double calculate_sum(int n, double *a) { 
    double sum = 0; 
    int i; 

    #pragma omp critical 
    { 
     printf("Num devices: %d\n", acc_get_num_devices(acc_device_nvidia)); 

     #pragma acc enter data copyin(a[0:n]) 

     #pragma acc parallel 
     #pragma acc loop 
     for(i=0;i<n;i++) { 
      sum += a[i]; 
     } 

     #pragma acc exit data delete(a[0:n]) 
    } 

    return sum; 
} 


int ret_num_dev(int index) { 
    int dev = acc_get_num_devices(acc_device_nvidia); 
    if(dev == acc_device_nvidia) 
     printf("Num devices: %d - Current device: %d\n", dev, acc_get_device()); 
    return dev; 
} 

다음 명령을 내장 라이브러리 :

pgcc -acc -ta=nvidia:nordc -fPIC -c libmyacc.c

pgcc -shared -Wl,-soname,libctest.so.1 -o libmyacc.so -L/opt/pgi/linux86-64/16.5/lib -L/usr/lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lgomp -lnuma -lpthread -lnspgc -lpgc -lm -lgcc -lc -lgcc libmyacc.o


마이 N 코드 :

gcc f1.c -L/opt/pgi/linux86-64/16.5/lib -L/usr/lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L. -laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lgomp -lnuma -lpthread -lnspgc -lpgc -lm -lgcc -lc -lgcc -lmyacc


내가 뭔가 잘못하고 있는가 :

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


#define N 1000 

// to make sure library is loaded just once for whole program 
static void *lib_handle = NULL; 
static int lib_loaded = 0; 
static double (*calculate_sum2)(int , double *); 

void call_lib_so() { 

    // load library just once and init the function pointer 
    // to function in the library. 
    if(lib_loaded == 0) { 
     lib_loaded = 1; 
     char *error; 

     lib_handle = dlopen("/home/millad/temp/gcc-pgi/libmyacc.so", RTLD_NOW); 
     if (!lib_handle) { 
      fprintf(stderr, "%s\n", dlerror()); 
      exit(1); 
     } 

     calculate_sum2 = (double (*)(int , double *)) dlsym(lib_handle, "calculate_sum"); 
     if ((error = dlerror()) != NULL) { 
      fprintf(stderr, "%s\n", error); 
      exit(1); 
     } 
    } 


    // execute the function per call 
    int n = N, i; 
    double *a = (double *) malloc(sizeof(double) * n); 
    for(i=0;i<n;i++) 
     a[i] = 1.0 * i; 
    double sum = (*calculate_sum2)(n, a); 
    free(a); 
    printf("-------- SUM: %.3f\n", sum); 



// dlclose(lib_handle); 
} 


extern double calculate_sum(int n, double *a); 

int main() { 

    // allocation and initialization of an array 
    double *a = (double*) malloc(sizeof(double) * N); 
    int i; 
    for(i=0;i<N;i++) { 
     a[i] = (i+1) * 1.0; 
    } 

    // access and run OpenACC region with all threads 
    #pragma omp parallel 
    call_lib_so(); 

    return 0; 
} 

그리고 내 앞의 질문에 매트에 의해 설명 된 바와 같이 GCC를 사용하여 명령을 다음 내 주요 코드를 내장? 위의 단계가 정확합니까?

답변

1

코드가 올바르게 작동합니다. 나는 당신이 나열한 것을 사용하려했지만 "libctest.so"를 제거하고 dlopen이 그렇게하는 위치를 변경하고 gcc 컴파일 라인에 "-DN = 1024"를 추가해야했습니다. 그 후, 컴파일되어 잘 돌아갔다.

% pgcc -acc -ta=nvidia:nordc -fPIC -c libmyacc.c -V16.5        
% pgcc -shared -o libmyacc.so -L/opt/pgi/linux86-64/16.5/lib -L/usr/lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lgomp -lnuma -lpthread -lnspgc -lpgc -lm -lgcc -lc -lgcc libmyacc.o -V16.5 
% gcc f1.c -L/proj/pgi/linux86-64/16.5/lib -L/usr/lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L. -laccapi -laccg -laccn -laccg2 -ldl -lcudadevice -lgomp -lnuma -lpthread -lnspgc -lpgc -lm -lgcc -lc -lgcc -lmyacc -DN=1024 
% ./a.out 
Num devices: 8 
-------- SUM: 523776.000 
+0

감사합니다. @ mat-colgrove. 죄송합니다'libctest.so'. 오타였습니다. 마지막으로 여기에 복사하여 붙여 넣은 후 libmyacc.so로 변경했습니다. ** 그러나 **, 나는'gcc'에 전달 된 옵션에 실수를했다. gcc에서'-fopenmp'를 사용하고 (대답 3 행), 라이브러리에서'omp critical'줄을 지우면, ** 가끔'cuMemFreeHost가 반환 한 에러 1 : 잘못된 값'에러가납니다. – Millad

+1

PGI 옵션에 "-nomp"를 추가하십시오. PGI와 GNU의 OpenMP 런타임은 호환되지 않으므로 문제가 될 수 있습니다. 이것이 나를 위해 일하는 동안, 바이너리는 주기적으로 seg fault를 얻는다. 비록 이것이 OpenACC 코드 주위에 매크로 가드를 놓고 GNU만으로 만들었 기 때문에 발생했습니다. 그래서 관련이 없다고 생각하지도 않고 자세히 조사하지도 않았습니다. –

+0

이 질문에 도움을 주신 Thanks Mat. 라이브러리를 컴파일하기 위해'-nomp'를 추가했습니다. 그러나 루프에서 함수를 호출 할 때'Segmentation fault' 오류가 발생합니다. 나는 단순히 calculate_sum을 1000 번처럼 호출하지만, 처음 7 번째 또는 8 번째 반복에서는 오류로 멈 춥니 다. 이것은 GDB가 나에게 보여주는 것입니다 : [GDB Output] (https://paste.ee/p/fLfOw). 어떤 아이디어? – Millad