为什么直接从共享库调用CUDA内核时会出现分段错误?
我尝试的方式(见问题标题)编译了它,但我得到了一个分段错误。那么,是我、CMake还是CUDA不支持来自共享库的直接内核调用呢?解决方案不一定要有CMake 进一步详情:为什么直接从共享库调用CUDA内核时会出现分段错误?,cuda,cmake,Cuda,Cmake,我尝试的方式(见问题标题)编译了它,但我得到了一个分段错误。那么,是我、CMake还是CUDA不支持来自共享库的直接内核调用呢?解决方案不一定要有CMake 进一步详情: 我有以下文件结构: testKernel.hpp __global__ void kernelTest( float x ); void callKernel( float x ); testKernel.cu #include "testKernel.hpp" __global__ void kernelTest( f
我有以下文件结构: testKernel.hpp
__global__ void kernelTest( float x );
void callKernel( float x );
testKernel.cu
#include "testKernel.hpp"
__global__ void kernelTest( float x ) {}
void callKernel( float x ) { kernelTest<<<1,1>>>( x ); }
使用以下工具编译和运行此文件:
cmake .; make && ./useKernel
导致分割错误。使用gdb的回溯跟踪是:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff75726bd in cudart::configData::addArgument(void const*, unsigned long, unsigned long) ()
from ./libtestKernelCall.so
(gdb) bt
#0 0x00007ffff75726bd in cudart::configData::addArgument(void const*, unsigned long, unsigned long) ()
from ./libtestKernelCall.so
#1 0x00007ffff7562eb7 in cudart::cudaApiSetupArgument(void const*, unsigned long, unsigned long) ()
from ./libtestKernelCall.so
#2 0x00007ffff7591ca2 in cudaSetupArgument ()
from ./libtestKernelCall.so
#3 0x00007ffff7556125 in __device_stub__Z10kernelTestf (__par0=3)
at /tmp/tmpxft_00003900_00000000-4_testKernel.cudafe1.stub.c:7
#4 0x00007ffff755616c in kernelTest (__cuda_0=3) at ./testKernel.cu:2
#5 0x000000000040280e in main () at ./useKernel.cu:6
使用测试(这意味着SEGFULT出现在这些设置中):
- 设置1
- cmake 3.4.1
- CUDA 7.0.27
- g++4.9.2
- 德比安
- 设置2
- cmake 3.3.1
- CUDA 6.5.14
- g++4.7.1
- 在CMakeList.txt中将
更改为SHARED
STATIC
- 使用包装函数
,而不是直接调用内核callKernel
make VERBOSE=1
获得的相关CMake命令。在可能的情况下,我将绝对路径更改为相对路径,但我不确定所有这些库路径。将这些命令放在一个文件中,并对该文件进行寻源,可正确地编译共享库和程序,从而导致分段错误。我还添加了command
,因为对我来说nvcc
的别名是`-ccbin``选项
make.sh
command nvcc "./testKernel.cu" -c -o "./testKernel.cu.o" -ccbin /usr/bin/cc -m64 -DtestKernelCall_EXPORTS -Xcompiler ,\"-fPIC\",\"-g\" -DNVCC -I/opt/cuda-7.0/include -I/opt/cuda-7.0/include
/usr/bin/c++ -fPIC -shared -Wl,-soname,libtestKernelCall.so -o libtestKernelCall.so ./testKernel.cu.o /opt/cuda-7.0/lib64/libcudart_static.a -lpthread /usr/lib/x86_64-linux-gnu/librt.so /usr/lib/x86_64-linux-gnu/libdl.so /opt/cuda-7.0/lib64/libcudart_static.a -lpthread /usr/lib/x86_64-linux-gnu/librt.so /usr/lib/x86_64-linux-gnu/libdl.so
command nvcc "./useKernel.cu" -c -o "./useKernel.cu.o" -ccbin /usr/bin/cc -m64 -Xcompiler ,\"-g\" -DNVCC -I/opt/cuda-7.0/include -I/opt/cuda-7.0/include
/usr/bin/c++ ./useKernel.cu.o -o useKernel -rdynamic /opt/cuda-7.0/lib64/libcudart_static.a -lpthread /usr/lib/x86_64-linux-gnu/librt.so /usr/lib/x86_64-linux-gnu/libdl.so libtestKernelCall.so /opt/cuda-7.0/lib64/libcudart_static.a -lpthread /usr/lib/x86_64-linux-gnu/librt.so /usr/lib/x86_64-linux-gnu/libdl.so -Wl,-rpath,"."
如果我将
-cudart shared
开关添加到每个nvcc命令中,则您的代码可以使用普通的nvcc
命令(而不是CMake)为我正确编译和运行。下面是一个完整的工作顺序:
$ cat testKernel.hpp
__global__ void kernelTest( float x );
void callKernel( float x );
$ cat testKernel.cu
#include "testKernel.hpp"
__global__ void kernelTest( float x ) {}
void callKernel( float x ) { kernelTest<<<1,1>>>( x ); }
$ cat useKernel.cu
#include <cstdio>
#include "testKernel.hpp"
int main( void )
{
kernelTest<<<1,1>>>( 3.0f );
//callKernel( 3.0f );
cudaDeviceSynchronize();
printf("OK\n");
return 0;
}
$ nvcc -shared -cudart shared -o test.so -Xcompiler -fPIC testKernel.cu
$ nvcc -cudart shared -o test test.so useKernel.cu
$ cuda-memcheck ./test
========= CUDA-MEMCHECK
OK
========= ERROR SUMMARY: 0 errors
$
在这种情况下,您不希望链接到:
/opt/cuda-7.0/lib64/libcudart_static.a
而是反对libcudart。所以:
/opt/cuda-7.0/lib64/libcudart.so
如果您正在直接编辑make.sh
,您可能希望在显示的/usr/bin/c++
命令行中进行更改。例如,如果我要修改我已经提出的编译序列,以反映您对主机C++编译器使用的链接,它看起来就是这样:
$ nvcc -c -Xcompiler -fPIC testKernel.cu
$ g++ -fPIC -shared -o test.so -L/usr/local/cuda/lib64 -lcudart testKernel.o
$ nvcc -c useKernel.cu
$ g++ -o test -L/usr/local/cuda/lib64 -lcudart test.so useKernel.o
$ cuda-memcheck ./test
========= CUDA-MEMCHECK
OK
========= ERROR SUMMARY: 0 errors
$
将set(CUDA\u USE\u STATIC\u CUDA\u RUNTIME OFF)
放在find\u包(需要CUDA)
之前将完成与set(CUDA\u库“${CUDA\u TOOLKIT\u ROOT\u DIR}/lib64/libcudart.so”)相当的工作。
这是对的扩展。
我使用了下面的CMakeLists.txt
,效果很好
cmake_minimum_required(VERSION 3.8)
project(cmake_and_cuda LANGUAGES CXX CUDA)
add_library(my_cu SHARED testKernel.cu testKernel.h)
target_link_libraries(my_cu PRIVATE cudart) #MUST!!
set(CMAKE_CUDA_FLAGS "-shared -cudart shared -Xcompiler -fPIC"
CACHE STRING "Use libcudart.dylib" FORCE)
set(CMAKE_MACOSX_RPATH FALSE)
add_executable(app useKernel.cu)
target_link_libraries(app PRIVATE cudart) #MUST!!
target_link_libraries(app PRIVATE my_cu)
我使用的是cmake3.10
,我的操作系统是osx EI Capitan 10.11.6
。
对我来说,如果我没有将CMAKE\u MACOSX\u RPATH
设置为FALSE
,我将得到一个库未加载
错误。也许对你来说没有必要
请注意,由于cmake3.8
,因此FindCUDA
被取代,因此设置CUDA\u USE\u STATIC\u CUDA\u RUNTIME
不会产生任何影响。
您可以查看和了解详细信息。
此外,还提供了一个关于如何在
cmake3.8
之后处理CUDA
的好例子 显然这是可能的。这就是库布拉斯和库夫特这样的图书馆work@talonmies:是吗?至少我用过cuFFT,像CufftC2Exec这样的调用不是直接的内核调用,它们是共享库中的包装器,然后调用内核?很可能是不相关的。即使没有cmake(Debian Jessie,g++4.9.2-10,cuda V7.0.27),我也能够重现这一点,所以至少不仅仅是你……你能提供运行make VERBOSE=1
的相关编译器调用吗谢谢你的时间。我需要将'-Xlinker-rpath,“.”
附加到nvcc-cudart shared-o test.so useKernel.cu
调用中。你的详细描述让我想到我可能应该使用cuda\u compile
而不是target\u link\u库
,但这也不起作用。就像你说的,make.sh
在一个简单的sed的/u static.a/.so/g'-i make.sh
之后工作。知道在findPackage之后添加set(CUDA\u库“${CUDA\u TOOLKIT\u ROOT\u DIR}/lib64/libcudart.so”)
会起作用,但看起来很脏<代码>CUDA_使用\u静态\u CUDA_运行时似乎被忽略,但我不确定如何设置它。
/opt/cuda-7.0/lib64/libcudart.so
$ nvcc -c -Xcompiler -fPIC testKernel.cu
$ g++ -fPIC -shared -o test.so -L/usr/local/cuda/lib64 -lcudart testKernel.o
$ nvcc -c useKernel.cu
$ g++ -o test -L/usr/local/cuda/lib64 -lcudart test.so useKernel.o
$ cuda-memcheck ./test
========= CUDA-MEMCHECK
OK
========= ERROR SUMMARY: 0 errors
$
cmake_minimum_required(VERSION 3.8)
project(cmake_and_cuda LANGUAGES CXX CUDA)
add_library(my_cu SHARED testKernel.cu testKernel.h)
target_link_libraries(my_cu PRIVATE cudart) #MUST!!
set(CMAKE_CUDA_FLAGS "-shared -cudart shared -Xcompiler -fPIC"
CACHE STRING "Use libcudart.dylib" FORCE)
set(CMAKE_MACOSX_RPATH FALSE)
add_executable(app useKernel.cu)
target_link_libraries(app PRIVATE cudart) #MUST!!
target_link_libraries(app PRIVATE my_cu)