【发布时间】:2014-01-31 17:24:50
【问题描述】:
以下程序使用cuSPARSE 测试密集到稀疏的转换。它在前几行输出中产生垃圾。但是,如果我将标有(2) 的行移到标有(1) 的行之后,程序就可以正常工作。谁能告诉我可能是什么原因?
编辑:
为了让演示更清晰,我用thrust重写了程序,同样的问题仍然存在。
编辑:
按照罗伯特的建议,我把它改回了没有thrust的版本,并添加了api级别的错误检查代码。
#include <iostream>
#include <cusparse_v2.h>
using std::cerr;
using std::cout;
using std::endl;
#define WRAP(x) do {x} while (0)
#define CHKcusparse(x) WRAP( \
cusparseStatus_t err = (x); \
if (err != CUSPARSE_STATUS_SUCCESS) { \
cerr << "Cusparse Error #" << int(err) << "\"TODO\" at Line " \
<< __LINE__ << " of " << __FILE__ << ": " << #x << endl; \
exit(1); \
} \
)
#define CHKcuda(x) WRAP( \
cudaError_t err = (x); \
if (err != cudaSuccess) { \
cerr << "Cuda Error #" << int(err) << ", \"" \
<< cudaGetErrorString(err) << "\" at Line " << __LINE__ \
<< " of " << __FILE__ << ": " << #x << endl; \
exit(1); \
} \
)
#define ALLOC(X, T, N) do { \
h##X = (T*) malloc(sizeof(T) * (N)); \
CHKcuda(cudaMalloc((void**)&d##X, sizeof(T) * (N))); \
} while(0)
int main() {
srand(100);
cusparseHandle_t g_cusparse_handle;
CHKcusparse(cusparseCreate(&g_cusparse_handle));
const int n = 100, in_degree = 10;
int nnz = n * in_degree, nn = n * n;
int *dnnz, *dridx, *dcols;
int *hnnz, *hridx, *hcols;
float *dvals, *dmat;
float *hvals, *hmat;
// (1) The number of non-zeros in each column.
ALLOC(nnz, int, n);
// The dense matrix.
ALLOC(mat, float, nn);
// The values in sparse matrix.
ALLOC(vals, float, nnz);
// (2) The row indices of the sparse matrix.
ALLOC(ridx, int, nnz);
// The column offsets of the sparse matrix.
ALLOC(cols, int, n+1);
// Fill and copy dense matrix and number of non-zeros.
for (int i = 0; i < nn; i++) {hmat[i] = rand();}
for (int i = 0; i < n; i++) {hnnz[i] = in_degree;}
CHKcuda(cudaMemcpyAsync(dnnz, hnnz, sizeof(int) * n, cudaMemcpyHostToDevice));
CHKcuda(cudaMemcpyAsync(dmat, hmat, sizeof(float) * nn, cudaMemcpyHostToDevice));
CHKcuda(cudaDeviceSynchronize());
// Perform dense to CSC format
cusparseMatDescr_t cspMatDesc;
CHKcusparse(cusparseCreateMatDescr(&cspMatDesc));
CHKcusparse(cusparseSdense2csc(
g_cusparse_handle, n, n, cspMatDesc, dmat, n,
dnnz, dvals, dridx, dcols
));
// Copy row indices back.
CHKcuda(cudaMemcpyAsync(hridx, dridx, sizeof(int) * nnz, cudaMemcpyDeviceToHost));
CHKcuda(cudaDeviceSynchronize());
CHKcusparse(cusparseDestroyMatDescr(cspMatDesc));
// Display row indices.
for (int i = 0; i < n; i++) {
for (int j = 0; j < in_degree; j++) {
std::cout << hridx[i * in_degree + j] << ", ";
}
std::cout << std::endl;
}
CHKcuda(cudaFree(dnnz));
CHKcuda(cudaFree(dvals));
CHKcuda(cudaFree(dridx));
CHKcuda(cudaFree(dcols));
CHKcuda(cudaFree(dmat));
free(hnnz);
free(hmat);
free(hvals);
free(hridx);
free(hcols);
return 0;
}
【问题讨论】:
-
没有错误检查?在向其他人寻求帮助之前,您应该利用 CUDA 和 cusparse API 的基本 API 级别错误检查。无论第 1 行或第 2 行的位置如何,您都有返回错误的 cusparse 函数。您声明每列 nnz 为 10,但实际上您正在初始化密集矩阵,每列有超过 10 个非零元素,这导致密集到稀疏的转换来炸毁。 Cusparse 提供了一个函数来预先计算每列的 nnz。但在您的情况下,您只需将
in_degree设置为 100 而不是 10 即可消除错误。 -
感谢您的提醒。我从一个大型代码库中提取它来提问。我已经测试了这些调用,它们都成功返回。至于密集矩阵,我打算将密集矩阵 n 乘以 n,然后将其转换为大小为 n 乘 n 的稀疏矩阵,每列有 10 个非零元素。如果这是设置,我调用转换函数的方式是否正确?还是我理解错了什么?
-
@RobertCrovella 对不起,我明白你的意思,你的意思是如果我的密集矩阵在每列中有超过 10 个非零元素,我不能调用每列 nnz 等于 10 的转换?转换不会自动选择 10 个最不为零的元素吗?
-
不,它不会自动选择 10 个最非零元素,(??)。如果您仔细考虑这一点,我想您会意识到,如果每列的 nnz 与您传递的矩阵不匹配,则结果可能会模棱两可。您传递的每列的 nnz 应与您传递的实际密集矩阵相匹配。如果您愿意,请使用cusparse function available for this purpose。当我运行您发布的第一个代码并测试 API 级别错误时,我在最后一次
cudaMemcpyAsync调用时收到错误。 -
你也可以看到你的推力版本的错误。使用
cuda-memcheck运行您的代码或查看proper cuda error checking(其中还讨论了推力错误检查)。如果您没有看到错误,则说明您的错误检查方法已损坏。
标签: cuda sparse-matrix