我的项目使用CMake进行构建,并使用Google Test进行自动化的单元测试。
我们才刚刚开始将CUDA代码添加到项目中。我有一个在一个应用程序中工作的内核,包括通过单元测试。现在,我正在尝试将可重用代码抽象到共享库。我要做的就是重定位代码,现在它在运行时失败,显示为cudaErrorInvalidDeviceFunction
主要CMakeLists.txt:
project( myProject
LANGUAGES CXX CUDA
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_compile_options(
$<$<COMPILE_LANGUAGE:CUDA>:-gencode=arch=compute_60,code=sm_60>
$<$<COMPILE_LANGUAGE:CUDA>:-gencode=arch=compute_35,code=sm_35>
$<$<COMPILE_LANGUAGE:CUDA>:-gencode=arch=compute_30,code=compute_30>
# $<$<COMPILE_LANGUAGE:CUDA>:--fmad=false>
)
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-ffast-math>
$<$<COMPILE_LANGUAGE:CUDA>:--use_fast_math>
)
add_subdirectory(dsp)
在原始应用程序中,CUDA和C ++代码位于单独的静态库中,以方便单元测试。它们是分开的,因为当我将它们放在一起时,CMake会抱怨无法找到文件。目前,这不是我的问题,但是我注意到,当我重新组织代码时,我能够将它们放在同一个库中。
我的共享库CMakeLists.txt:
set(myTarget dsp)
add_library( ${myTarget} SHARED
BlackmanHarris.cpp
BlackmanHarrisCU.cu
FindPeakKernel.cu
cubBlockSort.cu
)
set_target_properties( ${myTarget} PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
POSITION_INDEPENDENT_CODE ON
)
target_link_libraries( ${myTarget}
${CUDA_LIBRARIES}
)
install(TARGETS ${myTarget} DESTINATION lib64)
# unit testing
add_subdirectory(unit)
我的某些代码是使用thrust
编写的;仍然可以在共享库中使用。主要是由于我自己的无知,一个特定的内核仍被显式调用。内核执行的操作无关紧要。我将其简化为以下代码,但仍然失败:
void __global__ printKernel()
{
auto txBase = int(blockIdx.x * blockDim.x);
auto dataIndex = txBase + threadIdx.x;
printf("printKernel:%d base=%d idx=%d\n", threadIdx.x, txBase, dataIndex);
__syncthreads();
return;
}
void runFindPeakKernel(int nBlocks, int nThreads,
float* output,
thrust::complex<float> const* input,
int fftSize, int numElement)
{
gpuCheck(cudaPeekAtLastError());
printf("runFindPeakKernel(%d, %d, ..., %d)\n", nBlocks, nThreads, numElement);
printKernel<<<1,1>>>();
gpuCheck(cudaDeviceSynchronize());
}
该测试使用的测试夹具可以生成400万个复杂样本,因此与此处无关。测试装置调用代码很简单:
TEST_F(FindPeakKernelTest, fft256)
{
auto constexpr fftSize = int(256);
thrust::device_vector<container_type::value_type> gInput = input;
thrust::device_vector<float> gResult( gInput.size() );
int nThreads = (input.size() > 256 ? 256 : input.size());
int nBlocks = ((input.size() - 1) / nThreads) + 1;
runFindPeakKernel(nBlocks, nThreads,
thrust::raw_pointer_cast(gResult.data()),
thrust::raw_pointer_cast(gInput.data()),
fftSize, gInput.size());
ASSERT_EQ(cudaPeekAtLastError(), cudaSuccess);
}
请注意,我的最小测试中没有使用任何设备内存,但是其分配和初始化确实成功。
内核调用导致cudaErrorInvalidDeviceFunction
错误。如果我将完全相同的代码放在文件中,然后将其包装在main
函数中,那么它将起作用。
这方面的大多数问题都是过时的。 CUDA从3.8开始就已经支持CUDA作为一流语言,至少从5.0开始就在CUDA中实现了可分离的编译。
在撰写本文时,SO提供了this作为相关问题,并且已经结束。特别是Robert Crovella's answer有有趣的见解,但不是CMake解决方案。 Jiang距离更近,但我无法使他的方法起作用。
顺便说一句,我遇到了this tip来确定内核调用参数。我知道这与我的问题无关,但只是出于娱乐目的,我将其放入了内核驱动程序。在内核被调用之前,我从cudaOccupancyMaxPotentialBlockSize
中得到了同样的错误。
这使我怀疑Robert所建议的共享链接与静态链接,使我认为我只是不具备CMake魔术功能。特别是,我注意到我的图书馆正在这样链接:
[ 19%] Linking CUDA device code CMakeFiles/dsp.dir/cmake_device_link.o
cd build-Debug/dsp && /usr/bin/cmake3 -E cmake_link_script CMakeFiles/dsp.dir/dlink.txt --verbose=1
/usr/local/cuda/bin/nvcc -g -Xcompiler=-fPIC -Wno-deprecated-gpu-targets -shared -dlink CMakeFiles/dsp.dir/BlackmanHarris.cpp.o CMakeFiles/dsp.dir/BlackmanHarrisCU.cu.o CMakeFiles/dsp.dir/FindPeakKernel.cu.o CMakeFiles/dsp.dir/cubBlockSort.cu.o -o CMakeFiles/dsp.dir/cmake_device_link.o -L/usr/local/cuda/targets/x86_64-linux/lib/stubs -L/usr/local/cuda/targets/x86_64-linux/lib -lcudadevrt -lcudart_static -lrt -lpthread -ldl
[ 20%] Linking CXX shared library libdsp.so
build-Debug/dsp && /usr/bin/cmake3 -E cmake_link_script CMakeFiles/dsp.dir/link.txt --verbose=1
/usr/local/bin/g++ -fPIC -g -Wall -Wextra -shared -Wl,-soname,libdsp.so -o libdsp.so CMakeFiles/dsp.dir/BlackmanHarris.cpp.o CMakeFiles/dsp.dir/BlackmanHarrisCU.cu.o CMakeFiles/dsp.dir/FindPeakKernel.cu.o CMakeFiles/dsp.dir/cubBlockSort.cu.o CMakeFiles/dsp.dir/cmake_device_link.o -L/usr/local/cuda/targets/x86_64-linux/lib/stubs -L/usr/local/cuda/targets/x86_64-linux/lib -Wl,-rpath,:::::::::::::::: -lcudadevrt -lcudart_static -lrt -lpthread -ldl
对于那些不太熟悉CMake的人,我向您保证代码 正在针对目标体系结构进行编译。这是CMake发出的相关编译命令:
[ 19%] Building CUDA object dsp/CMakeFiles/dsp.dir/FindPeakKernel.cu.o
cd build-Debug/dsp && /usr/local/cuda/bin/nvcc -DLINUX -Ddsp_EXPORTS -g -Xcompiler=-fPIC --compiler-options=-fdiagnostics-color=never -gencode=arch=compute_35,code=sm_35 -gencode=arch=compute_60,code=sm_60 -gencode=arch=compute_30,code=compute_30 --use_fast_math -x cu -dc src/dsp/FindPeakKernel.cu -o CMakeFiles/dsp.dir/FindPeakKernel.cu.o