2016-07-07 76 views
1

启用OpenACC的-PGI库之前,我问关于建立一个静态库与PGI的问题,并将其链接到一个内建GCC程序:c - Linking a PGI OpenACC-enabled library with gccÇ - 动态链接用gcc

现在,我有同样的问题,但动态。我怎样才能用gcc构建一个程序,而我的库是用PGI动态构建的

而且也考虑到以下事实:

  • 我想他们都承认同OpenMP的编译和程序太多。例如,当我在库中使用OpenMP关键区域时,整个程序应该在该部分中进行序列化。

  • OpenACC pragmas用于使用PGI构建的库中。

  • 加载库在我的应用程序中完全动态。我的意思是使用dlopen来打开lib和dlsym来查找函数。

  • 我也希望我的线程能够同时访问GPU进行数据传输和/或计算。有关更多详细信息,请参阅以下代码片段。

例如,建筑物下面的lib和主代码发出这样的错误:call to cuMemcpyHtoDAsync returned error 1: Invalid value


注:在构建以下代码,我故意用来代替PGI的OpenMP库LibGOMP(-lgomp)( -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个代码:

#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

Thanks @ mat-colgrove。对不起'libctest.so'。这是一个错字。在我的最后,我将它复制粘贴到此处并工作后,将其更改为'libmyacc.so'。 **然而**,我在传递给'gcc'的选项时犯了一个错误。当我在gcc上使用'-fopenmp'(你的回答中的第3行)启用OpenMP并删除库中的'omp critical'行时,**有时会**给我'调用cuMemFreeHost返回错误1:无效值错误。 – Millad

+1

尝试在PGI选项中添加“-nomp”。 PGI和GNU的OpenMP运行时间不兼容,这可能会导致您的问题。请注意,尽管这适用于我,但二进制文件确实会周期性地发生seg故障。但是,这也发生在我将OpenACC代码放在宏观卫士周围,并且仅使用GNU构建的时候,所以我认为这并不相关,也没有进一步调查。 –

+0

感谢您对此问题的帮助。我添加了'-nomp'来编译库。但是,当我在循环库中调用函数时,出现'Segmentation fault'错误。我简单地称'calculate_sum'为1000次,但在第7次或第8次迭代时它会停止并显示错误。这是GDB显示给我的:[GDB输出](https://paste.ee/p/fLfOw)。有任何想法吗? – Millad