cuSPARSE库cusparseScsr2csc函数CSR转CSC返回异常结果求助
cuSPARSE csr2csc 转换错误排查方案
核心排查点
参数传递错误
- 确认
cusparseScsr2csc的nnz、m、n参数匹配CSR矩阵实际维度:CSR的m是行数,转置为CSC后n对应原行数,避免维度颠倒。 - 检查
copyValues参数:需设为CUSPARSE_ACTION_NUMERIC才会复制数值,CUSPARSE_ACTION_SYMBOLIC仅处理索引,数值不会被转置。 - 确认
idxBase参数:CSR矩阵索引是0-based还是1-based,必须与函数参数一致,比如原矩阵是0-based则传CUSPARSE_INDEX_BASE_ZERO。
- 确认
内存分配与拷贝问题
- 检查设备端内存分配是否成功:调用
cudaMalloc后判断返回值,避免空指针。 - 主机到设备的
cudaMemcpy方向是否正确,不要误写为cudaMemcpyDeviceToHost。 - 转置后的CSC设备内存是否足够:
cscColPtr的长度是n+1(n为原矩阵行数),不能少分配一个元素。
- 检查设备端内存分配是否成功:调用
cuSPARSE句柄与状态检查
- 初始化
cusparseHandle_t后检查返回值,确保句柄创建成功。 - 每次调用
cusparseScsr2csc后立即检查返回的cusparseStatus_t状态码,比如CUSPARSE_STATUS_INVALID_VALUE、CUSPARSE_STATUS_ALLOC_FAILED可直接定位问题。
- 初始化
数据类型与矩阵合法性
- 确认CSR矩阵的
rowPtr严格递增,且最后一个元素等于nnz,非法CSR结构会导致转置逻辑崩溃。 - 检查
colInd的索引是否在合法范围内(0到n-1或1到n,对应索引基)。 - MX150是Pascal架构,CUDA 9.2支持,但要确保编译时架构参数(
-arch=sm_61)正确匹配,避免二进制不兼容。
- 确认CSR矩阵的
调试建议
- 用小规模测试矩阵的主机端数据打印对比,比如手动计算3x3稀疏矩阵的转置CSC格式,再和程序输出对比。
- 用
cudaMemcpy把设备端CSC数据拷回主机,逐元素检查索引和数值,定位是索引错误还是数值错误。 - 注释掉封装函数,编写最简测试代码排除封装层逻辑错误,示例代码:
#include <cusparse.h> #include <iostream> int main() { cusparseHandle_t handle; cusparseCreate(&handle); // 3x3 CSR矩阵:[[1,0,2],[0,3,0],[4,0,5]] const int m = 3, n = 3, nnz = 5; float h_csrVal[] = {1,2,3,4,5}; int h_csrRowPtr[] = {0,2,3,5}; int h_csrColInd[] = {0,2,1,0,2}; float *d_csrVal, *d_cscVal; int *d_csrRowPtr, *d_csrColInd, *d_cscColPtr, *d_cscRowInd; cudaMalloc(&d_csrVal, nnz*sizeof(float)); cudaMalloc(&d_csrRowPtr, (m+1)*sizeof(int)); cudaMalloc(&d_csrColInd, nnz*sizeof(int)); cudaMalloc(&d_cscVal, nnz*sizeof(float)); cudaMalloc(&d_cscColPtr, (n+1)*sizeof(int)); cudaMalloc(&d_cscRowInd, nnz*sizeof(int)); cudaMemcpy(d_csrVal, h_csrVal, nnz*sizeof(float), cudaMemcpyHostToDevice); cudaMemcpy(d_csrRowPtr, h_csrRowPtr, (m+1)*sizeof(int), cudaMemcpyHostToDevice); cudaMemcpy(d_csrColInd, h_csrColInd, nnz*sizeof(int), cudaMemcpyHostToDevice); cusparseStatus_t status = cusparseScsr2csc(handle, m, n, nnz, d_csrVal, d_csrRowPtr, d_csrColInd, d_cscVal, d_cscColPtr, d_cscRowInd, CUSPARSE_ACTION_NUMERIC, CUSPARSE_INDEX_BASE_ZERO); std::cout << "Status code: " << status << std::endl; // 打印状态码排查 float h_cscVal[5]; int h_cscColPtr[4], h_cscRowInd[5]; cudaMemcpy(h_cscVal, d_cscVal, nnz*sizeof(float), cudaMemcpyDeviceToHost); cudaMemcpy(h_cscColPtr, d_cscColPtr, (n+1)*sizeof(int), cudaMemcpyDeviceToHost); cudaMemcpy(h_cscRowInd, d_cscRowInd, nnz*sizeof(int), cudaMemcpyDeviceToHost); // 打印结果 std::cout << "CSC Val: "; for(int i=0;i<nnz;i++) std::cout << h_cscVal[i] << " "; std::cout << "\nCSC ColPtr: "; for(int i=0;i<n+1;i++) std::cout << h_cscColPtr[i] << " "; std::cout << "\nCSC RowInd: "; for(int i=0;i<nnz;i++) std::cout << h_cscRowInd[i] << " "; cusparseDestroy(handle); cudaFree(d_csrVal); cudaFree(d_csrRowPtr); cudaFree(d_csrColInd); cudaFree(d_cscVal); cudaFree(d_cscColPtr); cudaFree(d_cscRowInd); return 0; }
- 用CUDA自带的
cuda-memcheck工具检测内存越界或非法访问,快速定位内存相关隐蔽错误。
内容的提问来源于stack exchange,提问作者yys_c
相关产品推荐
相关产品推荐

