cmake - cooperative_groups::this_grid() 导致任何 CUDA API 调用返回 'unknown error'

标签 cmake cuda gpu gpu-cooperative-groups

按照 CUDA samples 中的相同步骤操作使用 cooperative_groups::this_grid().sync() 启动内核并跨网格同步导致任何 CUDA API 调用失败。使用时 cooperative_groups::this_thread_block().sync()工作正常并给出正确的结果。

我使用了以下代码和 CMakeLists.txt (cmake 版本 3.11.1)在 TITAN V GPU(驱动程序版本 410.73)和 Ubuntu 16.04.5 LTS 上使用 CUDA 10 进行测试。该代码也可在 github 上获取。以便于重现错误。

代码读取一个数组,然后将其反转(从 [0 1 2 ... 9][9 8 7 ... 0] )。为此,每个线程从同步数组中读取单个元素,然后将其元素写入正确的目标。可以轻松修改代码以确保 this_thread_block().sync()工作正常。只需更改 arr_size小于 1024 并使用 cg::thread_block barrier = cg::this_thread_block();反而。

test_cg.cu

#include <cuda_runtime_api.h>
#include <stdio.h>
#include <stdint.h>
#include <cstdint>
#include <numeric>
#include <cuda.h>
#include <cooperative_groups.h>
namespace cg = cooperative_groups;

//********************** CUDA_ERROR
inline void HandleError(cudaError_t err, const char *file, int line) {
    //Error handling micro, wrap it around function whenever possible
    if (err != cudaSuccess) {
        printf("\n%s in %s at line %d\n", cudaGetErrorString(err), file, line);

#ifdef _WIN32
        system("pause");
#else
        exit(EXIT_FAILURE);
#endif
    }
}
#define CUDA_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))
//******************************************************************************


//********************** cg kernel 
__global__ void testing_cg_grid_sync(const uint32_t num_elements,
    uint32_t *d_arr){
    uint32_t tid = threadIdx.x + blockDim.x*blockIdx.x;

    if (tid < num_elements){

        uint32_t my_element = d_arr[tid];

        //to sync across the whole grid 
        cg::grid_group barrier = cg::this_grid();

        //to sync within a single block 
        //cg::thread_block barrier = cg::this_thread_block();

        //wait for all reads 
        barrier.sync();

        uint32_t tar_id = num_elements - tid - 1;

        d_arr[tar_id] = my_element;
    }
}
//******************************************************************************


//********************** execute  
void execute_test(const int sm_count){

    //host array 
    const uint32_t arr_size = 1 << 20; //1M 
    uint32_t* h_arr = (uint32_t*)malloc(arr_size * sizeof(uint32_t));
    //fill with sequential numbers
    std::iota(h_arr, h_arr + arr_size, 0);

    //device array 
    uint32_t* d_arr;
    CUDA_ERROR(cudaMalloc((void**)&d_arr, arr_size*sizeof(uint32_t)));
    CUDA_ERROR(cudaMemcpy(d_arr, h_arr, arr_size*sizeof(uint32_t),
        cudaMemcpyHostToDevice));

    //launch config
    const int threads = 512;

    //following the same steps done in conjugateGradientMultiBlockCG.cu 
    //cuda sample to launch kernel that sync across grid 
    //https://github.com/NVIDIA/cuda-samples/blob/master/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG.cu#L436

    int num_blocks_per_sm = 0;
    CUDA_ERROR(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&num_blocks_per_sm,
        (void*)testing_cg_grid_sync, threads, 0));

    dim3 grid_dim(sm_count * num_blocks_per_sm, 1, 1), block_dim(threads, 1, 1);

    if(arr_size > grid_dim.x*block_dim.x){
         printf("\n The grid size (numBlocks*numThreads) is less than array size.\n");
         exit(EXIT_FAILURE);
    }
    printf("\n Launching %d blocks, each containing %d threads", grid_dim.x,
        block_dim.x);

    //argument passed to the kernel     
    void *kernel_args[] = {
        (void *)&arr_size,
        (void *)&d_arr, };


    //finally launch the kernel 
    cudaLaunchCooperativeKernel((void*)testing_cg_grid_sync,
        grid_dim, block_dim, kernel_args);


    //make sure everything went okay
    CUDA_ERROR(cudaGetLastError());
    CUDA_ERROR(cudaDeviceSynchronize());


    //get results on the host 
    CUDA_ERROR(cudaMemcpy(h_arr, d_arr, arr_size*sizeof(uint32_t),
        cudaMemcpyDeviceToHost));

    //validate 
    for (uint32_t i = 0; i < arr_size; i++){
        if (h_arr[i] != arr_size - i - 1){
            printf("\n Result mismatch in h_arr[%u] = %u\n", i, h_arr[i]);
            exit(EXIT_FAILURE);
        }
    }
}
//******************************************************************************

int main(int argc, char**argv) {

    //set to Titan V
    uint32_t device_id = 0;
    cudaSetDevice(device_id);

    //get sm count 
    cudaDeviceProp devProp;
    CUDA_ERROR(cudaGetDeviceProperties(&devProp, device_id));
    int sm_count = devProp.multiProcessorCount;

    //execute 
    execute_test(sm_count);

    printf("\n Mission accomplished \n");
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.8 FATAL_ERROR)

set(PROJECT_NAME "test_cg")
project(${PROJECT_NAME} LANGUAGES CXX CUDA)  

#default build type is Release
if (CMAKE_BUILD_TYPE STREQUAL "")
    set(CMAKE_BUILD_TYPE Release)
endif ()

SET(CUDA_SEPARABLE_COMPILATION ON)

########## Libraries/flags Starts Here ######################
find_package(CUDA REQUIRED)
include_directories("${CUDA_INCLUDE_DIRS}")
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}; -lineinfo; -std=c++11; -expt-extended-lambda; -O3; -use_fast_math; -rdc=true;)
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-gencode=arch=compute_70,code=sm_70) #for TITAN V
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -Wall -std=c++11")
########## Libraries/flags Ends Here ######################


########## inc/libs/exe/features Starts Here ######################
set(CMAKE_INCLUDE_CURRENT_DIR ON)
CUDA_ADD_EXECUTABLE(${PROJECT_NAME} test_cg.cu)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE  ON)
set_target_properties(${PROJECT_NAME} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)    
target_link_libraries(${PROJECT_NAME} ${CUDA_LIBRARIES} ${CUDA_cudadevrt_LIBRARY})
########## inc/libs/exe/features Ends Here ######################

运行此代码会给出:

unknown error in /home/ahdhn/test_cg/test_cg.cu at line 67

这是使用 cudaMalloc 的第一行。我通过查询 __CUDA_ARCH__ 确保代码已编译为正确的架构来自设备的结果是 700。如果您发现我在代码或 CMakeLists.txt 中做错了什么,请告诉我。文件。

最佳答案

在外部帮助下,使代码正常工作的解决方案是添加 string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_70,code=sm_70 --cudart shared")第二个之后set(CUDA_NVCC_FLAGS..... 。原因是我只有libcudadevrt.a在我的/usr/local/cuda-10.0/lib64/下因此我必须向 CUDA 发送信号以链接共享/动态运行时库,因为默认情况下是链接到静态。 string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_70,code=sm_70")第二个之后set(CUDA_NVCC_FLAGS..... 。原因是sm_70标志未正确传递给链接器。

此外,仅使用 CUDA_NVCC_FLAGS只会通过sm_70信息传递给编译器而不是链接器。仅使用CMAKE_NVCC_FLAGS时将报告error: namespace "cooperative_groups" has no member "grid_group"错误。

关于cmake - cooperative_groups::this_grid() 导致任何 CUDA API 调用返回 'unknown error',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53492528/

相关文章:

android - 在运行时加载多个共享库在 Android 中不起作用

CUDA 寄存器使用

c++ - 适用于 Windows 和 Linux 的 OpenCL 程序中的 GCN ISA 程序集

python - 在 Theano 中执行期间选择 GPU

c++ - CUDA 在执行期间结合线程独立(??)变量

opencv - GpuMat 上传小图片太慢

c++ - 使用 CPack 时防止为已安装的共享库创建名称链接

c++ - CMake <PROJECT-NAME>_SOURCE_DIR 变量作用域

cmake add_subdirectory 与其他 cmake 文件名而不是 CMakeLists.txt

java - cublasSgemm与jcuda批量使用