我编写的方式(请参阅问题标题),但我得到了分段错误。那么我,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 ); }
useKernel.cu
#include <cstdio>
#include "testKernel.hpp"
int main( void )
{
kernelTest<<<1,1>>>( 3.0f );
//callKernel( 3.0f );
printf("OK\n");
return 0;
}
的CMakeLists.txt
cmake_minimum_required(VERSION 3.3.1)
project(testKernelCall)
find_package(CUDA REQUIRED)
cuda_add_library( ${PROJECT_NAME} SHARED testKernel.cu testKernel.hpp )
target_link_libraries( ${PROJECT_NAME} ${CUDA_LIBRARIES} )
cuda_add_executable("useKernel" useKernel.cu)
target_link_libraries("useKernel" ${PROJECT_NAME})
使用以下命令编译并运行:
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
经过测试(表示段错误出现在这些设置中):
设置1
设置2
有两种方法可以解决此错误:
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,"."
答案 0 :(得分:3)
如果我将nvcc
开关添加到每个 nvcc命令,您的代码将使用普通的-cudart shared
命令(而不是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
$
如果我在上述-cudart shared
命令的 上省略nvcc
,那么编译仍将继续进行,但在执行时我将看到上述的seg错误。在Fedora 20上使用CUDA 7.5进行测试。
根据我的测试,关于你的CMake设置,有必要链接对抗共享cudart。因此,将-cudart shared
添加到-c
命令(这是编译命令)是不够的。如果我不清楚,请注意。我上面的“编译”命令正在执行 编译并且在每一步都进行链接。)
与nvcc
关联时,正确的切换为-cudart shared
。但是,您的make.sh
表示最终链接由主机c ++编译器完成:
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,"."
在这种情况下,您不希望链接:
/opt/cuda-7.0/lib64/libcudart_static.a
但反对libcudart.so
:
/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
$
答案 1 :(得分:1)
在In [33]: stacked = np.random.randint(0,10,(1000,1000,100))
In [34]: %timeit stacked.shape[-1] - stacked[...,::-1].argmax(-1) - 1
1 loop, best of 3: 281 ms per loop
In [35]: %timeit (stacked == stacked.max(-1,keepdims=1)).cumsum(-1).argmax(-1)
1 loop, best of 3: 659 ms per loop
之前放set(CUDA_USE_STATIC_CUDA_RUNTIME OFF)
将完成相当于find_package(CUDA REQUIRED)
的工作
答案 2 :(得分:0)
这是Robert Crovella's answer的扩展。
我使用以下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)
我使用CMake 3.10
,我的操作系统是OS X EI Capitan 10.11.6
。
对我来说,如果我没有将CMAKE_MACOSX_RPATH
设置为FALSE
,我将收到Library not loaded
错误。也许对你来说没有必要。
请注意,由于CMake 3.8
,FindCUDA
被取代,因此设置CUDA_USE_STATIC_CUDA_RUNTIME
不会产生任何影响。
您可以查看this post和this document了解详情。
此外,this post提供了关于如何在CUDA
之后处理CMake 3.8
的一个很好的示例。