我尝试使用CUDA的cusolver库在GPU上执行QR分解。
我将问题减少到下面的例子。
基本上,几个步骤是:
cusolverDnCreate
cusolverDnDgeqrf_bufferSize
cusolverDnDgeqrf
不幸的是,最后一个命令通过返回CUSOLVER_STATUS_EXECUTION_FAILED
(int值= 6)系统地失败了,我无法弄清楚出了什么问题!
这是错误的代码:
#include <cusolverDn.h>
#include <cuda_runtime_api.h>
int main(void)
{
int N = 5, P = 3;
double *hostData;
cudaMallocHost((void **) &hostData, N * sizeof(double));
for (int i = 0; i < N * P; ++i)
hostData[i] = 1.;
double *devData;
cudaMalloc((void**)&devData, N * sizeof(double));
cudaMemcpy((void*)devData, (void*)hostData, N * sizeof(double), cudaMemcpyHostToDevice);
cusolverStatus_t retVal;
cusolverDnHandle_t solverHandle;
retVal = cusolverDnCreate(&solverHandle);
std::cout << "Handler creation : " << retVal << std::endl;
double *devTau, *work;
int szWork;
cudaMalloc((void**)&devTau, P * sizeof(double));
retVal = cusolverDnDgeqrf_bufferSize(solverHandle, N, P, devData, N, &szWork);
std::cout << "Work space sizing : " << retVal << std::endl;
cudaMalloc((void**)&work, szWork * sizeof(double));
int *devInfo;
cudaMalloc((void **)&devInfo, 1);
retVal = cusolverDnDgeqrf(solverHandle, N, P, devData, N, devTau, work, szWork, devInfo); //CUSOLVER_STATUS_EXECUTION_FAILED
std::cout << "QR factorization : " << retVal << std::endl;
int hDevInfo = 0;
cudaMemcpy((void*)devInfo, (void*)&hDevInfo, 1 * sizeof(int), cudaMemcpyDeviceToHost);
std::cout << "Info device : " << hDevInfo << std::endl;
cudaFree(devInfo);
cudaFree(work);
cudaFree(devTau);
cudaFree(devData);
cudaFreeHost(hostData);
cudaDeviceReset();
}
您是否在我的代码中看到任何明显错误,请告诉我们! 非常感谢。
答案 0 :(得分:2)
如果您在使用cuda代码时出现问题,则应始终使用proper cuda error checking并在寻求帮助之前使用cuda-memcheck
,运行代码。
您可能还想知道relevant CUDA/cusolver sample code中提供了完全有效的QR分解示例,并且还有示例代码in the documentation。
通过适当的错误检查,您可能已经发现:
这不正确:
cudaMalloc((void **)&devInfo, 1);
第二个参数是以字节为单位的大小,因此它应该是sizeof(int)
,而不是1.此错误会导致cudaMemcpyAsync
调用内部的cusolverDnDgeqrf
操作出错,会显示在cuda-memcheck
输出中。
这是不正确的:
cudaMemcpy((void*)devInfo, (void*)&hDevInfo, 1 * sizeof(int), cudaMemcpyDeviceToHost);
指针参数的顺序是目标 first ,后跟source。因此,您将这些参数反转,并且此调用将引发运行时API错误,如果您正在进行正确的错误检查(或在cuda-memcheck
输出中可见),则可以观察到该错误。
修复这些错误后,qrf调用实际上将返回零状态(无错误)。但是我们还没有完成(再次,正确的错误检查会让我们知道我们还没有完成。)
除了上述错误之外,您还发现了一些额外的大小调整错误。您的矩阵大小为N*P
,因此它有N*P
个元素,您在这里初始化了很多元素:
for (int i = 0; i < N * P; ++i)
hostData[i] = 1.;
但是你不是为主机上的那么多元素分配:
cudaMallocHost((void **) &hostData, N * sizeof(double));
或在此处的设备上:
cudaMalloc((void**)&devData, N * sizeof(double));
并且你没有在这里转移那么多元素:
cudaMemcpy((void*)devData, (void*)hostData, N * sizeof(double), cudaMemcpyHostToDevice);
因此,在上述3个案例中,如果您将N*sizeof(double)
更改为N*P*sizeof(double)
,则可以修复这些错误,然后代码运行时cuda-memcheck
报告没有错误,并且也没有任何API调用返回错误。