首页 > 解决方案 > 尝试使用 cuSPARSE 的 cusparseCsr2cscEx2() 函数执行矩阵转置时出现内部错误

问题描述

我需要使用 cuSPARSE 执行矩阵(CSR)的转置,但得到“内部错误”。我写我的代码是指如何在 cuSparse 中转置稀疏矩阵?https://docs.nvidia.com/cuda/cusparse/index.html#csr2cscEx2。为了更清楚,我试图通过将矩阵从格式 csr 转换为格式 csc 来执行转置。

我在 Nvidia GeForce GTX 1080 上运行,带有驱动程序 cuda_11.1.0。我正在使用 Windows 10。

以下是我的代码。您可以从https://github.com/NVIDIA/CUDALibrarySamples/tree/master/cuSPARSE/sparse2dense下载该文件夹,并将 sparse2dense_example.c 替换为我的代码。然后使用CMake进行配置和制作,这样也许你可以重现我的问题。

#include <cuda_runtime_api.h> // cudaMalloc, cudaMemcpy, etc.
#include <cusparse.h>         // cusparseSparseToDense
#include <stdio.h>            // printf
#include <stdlib.h>           // EXIT_FAILURE

#define CHECK_CUDA(func)                                                       \
{                                                                              \
    cudaError_t status = (func);                                               \
    if (status != cudaSuccess) {                                               \
        printf("CUDA API failed at line %d with error: %s (%d)\n",             \
               __LINE__, cudaGetErrorString(status), status);                  \
        return EXIT_FAILURE;                                                   \
    }                                                                          \
}

#define CHECK_CUSPARSE(func)                                                   \
{                                                                              \
    cusparseStatus_t status = (func);                                          \
    if (status != CUSPARSE_STATUS_SUCCESS) {                                   \
        printf("CUSPARSE API failed at line %d with error: %s (%d)\n",         \
               __LINE__, cusparseGetErrorString(status), status);              \
        return EXIT_FAILURE;                                                   \
    }                                                                          \
}

int main(void) {
    // CUSPARSE APIs
    cusparseHandle_t     handle = NULL;
    cusparseStatus_t status = (cusparseCreate(&handle));
    if (status != CUSPARSE_STATUS_SUCCESS) {
        printf("CUSPARSE API failed at line %d with error: %s (%d)\n", __LINE__, cusparseGetErrorString(status), status);
    }
    
    // Initialize matrix A
    // this matrix is the same as https://github.com/NVIDIA/CUDALibrarySamples/blob/master/cuSPARSE/sparse2dense/sparse2dense_example.c
    int   num_rows = 5;
    int   num_cols = 4;
    int   nnz = 11;
    int   h_csr_offsets[] = { 0, 3, 4, 7, 9, 11 };
    int   h_csr_columns[] = { 0, 2, 3, 1, 0, 2, 3, 1, 3, 1, 2 };
    float h_csr_values[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
                               7.0f, 8.0f, 9.0f, 10.0f, 11.0f };
    // Device memory management
    int* d_csr_offsets, * d_csr_columns;
    float* d_csr_values;
    CHECK_CUDA(cudaMalloc((void**)&d_csr_offsets, (num_rows + 1) * sizeof(int)))
    CHECK_CUDA(cudaMalloc((void**)&d_csr_columns, nnz * sizeof(int)))
    CHECK_CUDA(cudaMalloc((void**)&d_csr_values, nnz * sizeof(float)))

    CHECK_CUDA(cudaMemcpy(d_csr_offsets, h_csr_offsets, (num_rows + 1) * sizeof(int), cudaMemcpyHostToDevice))
    CHECK_CUDA(cudaMemcpy(d_csr_columns, h_csr_columns, nnz * sizeof(int), cudaMemcpyHostToDevice))
    CHECK_CUDA(cudaMemcpy(d_csr_values, h_csr_values, nnz * sizeof(float), cudaMemcpyHostToDevice))

    // Memory allocation of transpose A
    int* d_csr_offsets_AT, * d_csr_columns_AT;
    float* d_csr_values_AT;
    //first allocate memory to ATT
    CHECK_CUDA(cudaMalloc((void**)&d_csr_offsets_AT, (num_cols + 1) * sizeof(int)))
    CHECK_CUDA(cudaMalloc((void**)&d_csr_columns_AT, nnz * sizeof(int)))
    CHECK_CUDA(cudaMalloc((void**)&d_csr_values_AT, nnz * sizeof(float)))

    size_t buffer_temp_size;
    cusparseCsr2cscEx2_bufferSize(
        handle, num_rows, num_cols, nnz, h_csr_values, h_csr_offsets, h_csr_columns,
        d_csr_values_AT, d_csr_offsets_AT, d_csr_columns_AT, CUDA_R_32F, CUSPARSE_ACTION_NUMERIC,
        CUSPARSE_INDEX_BASE_ZERO, CUSPARSE_CSR2CSC_ALG1, &buffer_temp_size);
    void* buffer_temp = NULL;
    printf("buffer_temp_size is %zd\n", buffer_temp_size);
    CHECK_CUDA(cudaMalloc(&buffer_temp, buffer_temp_size))
    CHECK_CUSPARSE(cusparseCsr2cscEx2(handle, num_rows, num_cols, nnz, h_csr_values, h_csr_offsets, h_csr_columns,
        d_csr_values_AT, d_csr_offsets_AT, d_csr_columns_AT, CUDA_R_32F, CUSPARSE_ACTION_NUMERIC,
        CUSPARSE_INDEX_BASE_ZERO, CUSPARSE_CSR2CSC_ALG1, buffer_temp))
}

标签: cudacusparse

解决方案


该错误是由于您将指向主机数据的指针传递给打算处理设备数据的例程:

cusparseCsr2cscEx2_bufferSize(
    handle, num_rows, num_cols, nnz, h_csr_values, h_csr_offsets, h_csr_columns,
                                     ^             ^              ^

CHECK_CUSPARSE(cusparseCsr2cscEx2(handle, num_rows, num_cols, nnz, h_csr_values, h_csr_offsets, h_csr_columns,
                                                                   ^             ^              ^

当我将这些实例更改为您分配的设备数据时:

d_csr_values, d_csr_offsets, d_csr_columns

根据我的测试,您所询问的“内部错误”消失了。


推荐阅读