我的应用程序使用CUDA内核进行大量计算。出于好的理由(超出了本问题的范围),我使用共享对象/链接模型来动态加载目标文件,每个目标文件包含1个主机函数和1个CUDA内核。由于内核不能是extern
,因此这种内核的基本结构是:
__global__ kernel() { ...code... }
extern "C" void call_kernel() {
<<<GRID,BLOCK,SHMEM>>>kernel();
}
我使用主机功能,其唯一目的是调用内核。为了构建共享对象,我使用:
nvcc -arch=sm_20 -m64 --compiler-options -fPIC,-shared -link -o kernel0.o kernel0.cu
整个应用程序使用了大量这些内核,并且加载了dlopen()
。如果所有(构建/加载/执行)都停留在一台机器A上,整个过程就可以正常工作。
但是当我在机器B(cuda 4.1,NVIDIA C2050)上编译/构建共享对象时,以及稍后在机器A(cuda 4.0,GTX 480)上的dlopen
时,计算结果不会产生相同的结果好像共享对象也是在机器A上构建的。
这听起来很奇怪。是否在.o
文件中嵌入了一个CUBIN对象,其中包含独立于特定GPU架构的指令?
我知道建议使用相同的编译器版本进行构建和链接。同样,我有充分的理由说明为什么不在同一台机器上构建共享对象。
答案 0 :(得分:3)
我想要说的第一点是你在应用程序中根本没有使用CUBIN文件,而是使用CUDA fat二进制对象。这两件事情是不一样的。
但这不是问题的根源。您的问题在于CUDA运行时库。运行时API已进行版本控制,并且必须使用该版本运行为给定运行时API版本编译的任何代码。此外,运行时API库版本具有最低的驱动程序版本要求。您不能使用针对CUDA 4.1库构建的应用程序,并期望在具有CUDA 4.0库的计算机上运行它。 NVIDIA推荐的分发运行时API代码的方法是将运行时API库(libcudart)与您的应用程序一起分发,并指定代码所需的最小驱动程序版本。这可确保应用程序正常运行(最小驱动程序版本带来最低CUDA驱动程序API版本,分布式运行时API库带来完成要求)。
另一种方法是真正使用cubin文件并使用CUDA驱动程序API。它更具可移植性(在最低驱动程序版本要求范围内),但它在主机代码中也有更多功能。选择是你的。