将 PGI OpenACC 运行时库直接与 gcc 链接

Linking PGI OpenACC Runtime Library directly with gcc

我对直接从 GCC 编译的代码使用 PGI OpenACC 运行time API 感兴趣。

我注意到 PGI OpenACC 安装提供了两个 openacc.h header。一个用于 PGI(位于 include/openacc.h),另一个似乎与 GCC 兼容(etc/include_acc/openacc.h)。在 GCC 中使用第二个 header 是安全的吗?

到目前为止,我已经能够编译 & 运行 一个小测试:

#include <openacc.h>
#include <cuda_runtime_api.h>
#include <stdio.h>

int main()
{
   acc_init( acc_device_nvidia );

   int ndev = acc_get_num_devices( acc_device_nvidia );

   printf("Num OpenACC devices: %d\n", ndev);

   cudaGetDeviceCount(&ndev);

   printf("Num CUDA devices: %d\n", ndev);

   return 0;
}

使用 PGI:

pgcc -acc -ta=tesla,cuda8.0 -Mcuda ./test.c -o oacc_test.pgi

使用 GCC + PGI OpenACC:

gcc -isystem /usr/local/cuda-8.0/include -isystem /usr/local/pgi/linux86-64/17.4/etc/include_acc -o oacc_test.both test.c -L/usr/local/cuda-8.0/lib64 -Wl,-rpath,/usr/local/cuda-8.0/lib64 -lcudart -lcuda -L/usr/local/pgi/linux86-64/17.4/lib -Wl,-rpath,/usr/local/pgi/linux86-64/17.4/lib -laccapi -laccg -laccnc -laccn -laccg2 -ldl -lpgc -lm

使用 GCC + GCC OpenACC:(用于比较)

gcc -fopenacc -isystem /usr/local/cuda-8.0/include -o oacc_test.gnu test.c -L/usr/local/cuda-8.0/lib64 -Wl,-rpath,/usr/local/cuda-8.0/lib64 -lcudart -lcuda

并执行:

$ ./oacc_test.pgi 
Num OpenACC devices: 4
Num CUDA devices: 4
$ ./oacc_test.both 
Num OpenACC devices: 4
Num CUDA devices: 4
$ ./oacc_test.gnu 

libgomp: device type nvidia not supported

更多信息:

$ ldd oacc_test.pgi 
    linux-vdso.so.1 (0x00007ffd843f8000)
    libaccapi.so => /usr/local/pgi/linux86-64/17.4/lib/libaccapi.so (0x00007fa5a2b9f000)
    libaccg.so => /usr/local/pgi/linux86-64/17.4/lib/libaccg.so (0x00007fa5a2981000)
    libaccnc.so => /usr/local/pgi/linux86-64/17.4/lib/libaccnc.so (0x00007fa5a2777000)
    libaccn.so => /usr/local/pgi/linux86-64/17.4/lib/libaccn.so (0x00007fa5a2552000)
    libaccg2.so => /usr/local/pgi/linux86-64/17.4/lib/libaccg2.so (0x00007fa5a233c000)
    libcudapgi.so => /usr/local/pgi/linux86-64/17.4/lib/libcudapgi.so (0x00007fa5a213b000)
    libcudart.so.8.0 => /usr/local/cuda/lib64/libcudart.so.8.0 (0x00007fa5a1ed5000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fa5a1b49000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa5a1945000)
    libcudadevice.so => /usr/local/pgi/linux86-64/17.4/lib/libcudadevice.so (0x00007fa5a1731000)
    libpgmp.so => /usr/local/pgi/linux86-64/17.4/lib/libpgmp.so (0x00007fa5a14af000)
    libnuma.so => /usr/local/pgi/linux86-64/17.4/lib/libnuma.so (0x00007fa5a12ae000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa5a1091000)
    libpgc.so => /usr/local/pgi/linux86-64/17.4/lib/libpgc.so (0x00007fa5a0dae000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa5a0aaa000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa5a070b000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa5a04f2000)
    /lib64/ld-linux-x86-64.so.2 (0x000055767be3b000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa5a02ea000)

$ ldd oacc_test.both 
    linux-vdso.so.1 (0x00007ffe55753000)
    libcudart.so.8.0 => /usr/local/cuda/lib64/libcudart.so.8.0 (0x00007f7ddfe3c000)
    libcuda.so.1 => /usr/lib/x86_64-linux-gnu/libcuda.so.1 (0x00007f7ddf3d8000)
    libaccapi.so => /usr/local/pgi/linux86-64/17.4/lib/libaccapi.so (0x00007f7ddf1b8000)
    libaccg.so => /usr/local/pgi/linux86-64/17.4/lib/libaccg.so (0x00007f7ddef9a000)
    libaccnc.so => /usr/local/pgi/linux86-64/17.4/lib/libaccnc.so (0x00007f7dded90000)
    libaccn.so => /usr/local/pgi/linux86-64/17.4/lib/libaccn.so (0x00007f7ddeb69000)
    libaccg2.so => /usr/local/pgi/linux86-64/17.4/lib/libaccg2.so (0x00007f7dde955000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7dde751000)
    libpgc.so => /usr/local/pgi/linux86-64/17.4/lib/libpgc.so (0x00007f7dde46e000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7dde16a000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7ddddcb000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7dddbac000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f7ddd9a4000)
    libnvidia-fatbinaryloader.so.378.13 => /usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.378.13 (0x00007f7ddd753000)
    /lib64/ld-linux-x86-64.so.2 (0x00005593f06f5000)

$ ldd oacc_test.gnu 
    linux-vdso.so.1 (0x00007ffd967d7000)
    libcudart.so.8.0 => /usr/local/cuda/lib64/libcudart.so.8.0 (0x00007f9002679000)
    libcuda.so.1 => /usr/lib/x86_64-linux-gnu/libcuda.so.1 (0x00007f9001c15000)
    libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f90019e8000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f90017cb000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f900142c000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9001226000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f900101e000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9000d1a000)
    libnvidia-fatbinaryloader.so.378.13 => /usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.378.13 (0x00007f9000ac9000)
    /lib64/ld-linux-x86-64.so.2 (0x0000563eee684000)

那样使用 PGI OpenACC Runtime API 安全吗?

此外,Nvidia 提供的 CUDA 运行时间(通常在 /usr/local/cuda)和 PGI 提供的时间(在我的例子中是 /usr/local/pgi/linux86-64/2017/cuda)之间有什么区别吗? 我注意到 pgcc 使用它自己的安装路径中的 CUDA 7.5,但是当提供 -ta=cuda8.0 时,它使用 /usr/local/cuda 中的那个。有什么特殊原因吗?

PGI 编译对象可与 GNU 互操作,可以将 PGI OpenACC 编译代码与 GNU 编译对象混合使用。不过,OpenACC 运行时库不兼容,所以我建议不要混合使用 OpenACC 代码。请注意,GNU 对 OpenACC 的支持在其 7.0 版本中已经变得更好,所以当我为 PGI 工作时,我鼓励您尝试这两种编译器。需要注意的是他们 (GNU) 不支持 "kernels" 结构,因此您需要坚持使用 "parallel" 区域。

至于 CUDA 库,PGI 提供了我们编译您的 OpenACC 代码所需的所有库。不过,CUDA 库本身没有区别。我们不希望用户必须共同安装 CUDA SDK,它允许我们添加方便的标志,例如“-Mcudalib[=cublas|cufft|curand|cusolver|cusparse]”,因为我们知道这些库位于何处以及将我们自己的 Fortran 接口模块包含到这些库中。

除非您在编译行上设置了标志 "CUDAROOT=",否则“-ta=tesla:cuda8.0”应该使用位于“$PGI/linux86-64/2017/cuda/8 中的 PGI 提供的 CUDA 8.0 目录。 0”。您确定它正在使用 /usr/local/cuda 安装吗?您可以通过添加详细标志 (-v) 来仔细检查以查看编译器驱动程序正在执行什么,或者添加“-dryrun”以查看命令而不让驱动程序执行它们。

另一种可能性是您使用“-L”或“-Wl”标志指向 CUDA 安装(就像您对 GNU 所做的那样),在这种情况下,链接器将从这些库中获取 CUDA 库目录。虽然因为它们与我们提供的库相同,所以这应该不是问题。