为什么直接从共享库调用CUDA内核时会出现分段错误?

为什么直接从共享库调用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

我尝试的方式(见问题标题)编译了它,但我得到了一个分段错误。那么,是我、CMake还是CUDA不支持来自共享库的直接内核调用呢?解决方案不一定要有CMake

进一步详情:


我有以下文件结构:

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
    ,而不是直接调用内核
我真的不知道如何在没有CMake的情况下构建CUDA共享库。我知道如何构建CUDA静态库,但这种情况似乎适用于CMake,所以我没有在没有CMake的情况下测试它

下面是我使用
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)