c - 将支持 PGI OpenACC 的库与 gcc 动态链接
c - Dynamically linking a PGI OpenACC-enabled library with gcc
之前,我问了一个关于使用 PGI 创建 静态库 并将其链接到使用 gcc 构建的程序的问题:
现在,我有同样的问题,但是动态。当我的库是使用 PGI 构建的 动态 时,如何使用 gcc 构建程序?
此外,考虑到以下事实:
我希望它们都能识别相同的 OpenMP pragma 和例程。例如,当我在库中使用 OpenMP 关键区域时,整个程序应该在该部分进行序列化。
用 PGI 构建的库中使用了 OpenACC pragma。
在我的应用程序中完全动态加载库。我的意思是使用 dlopen
打开库并使用 dlsym
查找函数。
我还希望我的线程能够同时访问 GPU 以进行数据传输 and/or 计算。有关详细信息,请参阅以下代码片段。
例如,构建以下 lib 和主要代码会发出此错误:call to cuMemcpyHtoDAsync returned error 1: Invalid value
注意: 在构建以下代码时,我有意在这两种情况下使用 LibGOMP (-lgomp
) 而不是 PGI 的 OpenMP 库 (-lpgmp
),lib和主要。
库代码:
#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
主要代码:
#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 使用以下命令构建我的主要代码,如 Mat 在我上一个问题中所述:
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
我是不是做错了什么?以上步骤正确吗?
你的代码对我来说工作正常。我尝试使用您列出的内容,但需要删除 "libctest.so",更改 dlopen 获取 so 的位置,并在 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
之前,我问了一个关于使用 PGI 创建 静态库 并将其链接到使用 gcc 构建的程序的问题:
现在,我有同样的问题,但是动态。当我的库是使用 PGI 构建的 动态 时,如何使用 gcc 构建程序?
此外,考虑到以下事实:
我希望它们都能识别相同的 OpenMP pragma 和例程。例如,当我在库中使用 OpenMP 关键区域时,整个程序应该在该部分进行序列化。
用 PGI 构建的库中使用了 OpenACC pragma。
在我的应用程序中完全动态加载库。我的意思是使用
dlopen
打开库并使用dlsym
查找函数。我还希望我的线程能够同时访问 GPU 以进行数据传输 and/or 计算。有关详细信息,请参阅以下代码片段。
例如,构建以下 lib 和主要代码会发出此错误:call to cuMemcpyHtoDAsync returned error 1: Invalid value
注意: 在构建以下代码时,我有意在这两种情况下使用 LibGOMP (-lgomp
) 而不是 PGI 的 OpenMP 库 (-lpgmp
),lib和主要。
库代码:
#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
主要代码:
#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 使用以下命令构建我的主要代码,如 Mat 在我上一个问题中所述:
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
我是不是做错了什么?以上步骤正确吗?
你的代码对我来说工作正常。我尝试使用您列出的内容,但需要删除 "libctest.so",更改 dlopen 获取 so 的位置,并在 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