CUDA共享库运行时异常

时间:2019-07-22 18:23:17

标签: c++ cmake cuda

我的项目使用CMake进行构建,并使用Google Test进行自动化的单元测试。

我们才刚刚开始将CUDA代码添加到项目中。我有一个在一个应用程序中工作的内核,包括通过单元测试。现在,我正在尝试将可重用代码抽象到共享库。我要做的就是重定位代码,现在它在运行时失败,显示为cudaErrorInvalidDeviceFunction

  • CMake:3.13.5
  • g ++:7.3
  • CUDA:10.1
  • GPU测试:K40m

主要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

0 个答案:

没有答案