1

我尝试使用 CUDA 的 cusolver 库在 GPU 上执行 QR 分解。

我将我的问题简化为下面的示例。

基本上,这几个步骤是:

  1. 我分配内存并在主机上用 1 初始化了一个 [5x3] 矩阵,
  2. 我分配内存并在设备上复制矩阵
  3. 我初始化求解器处理程序cusolverDnCreate
  4. 我确定所需工作空间的大小cusolverDnDgeqrf_bufferSize
  5. 最后,尝试使用 QR 分解cusolverDnDgeqrf

不幸的是,最后一个命令通过返回CUSOLVER_STATUS_EXECUTION_FAILED(int value = 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();

}

您是否会在我的代码中看到任何明显的错误,请告诉我!非常感谢。

4

1 回答 1

3

每当您遇到 cuda 代码问题时,您应该始终使用正确的 cuda 错误检查并使用 运行您的代码cuda-memcheck然后再寻求帮助。

您可能还想知道,相关的 CUDA/cusolver 示例代码中给出了一个完整的 QR 分解示例,并且文档中也有示例代码。

通过适当的错误检查,您可能已经发现:

  1. 这是不正确的:

    cudaMalloc((void **)&devInfo, 1);
    

    第二个参数是以字节为单位的大小,因此它应该是sizeof(int),而不是 1。此错误会导致调用cudaMemcpyAsync内部操作中的错误,该错误cusolverDnDgeqrf会显示在cuda-memcheck输出中。

  2. 这是不正确的:

    cudaMemcpy((void*)devInfo, (void*)&hDevInfo, 1 * sizeof(int), cudaMemcpyDeviceToHost);
    

    指针参数的顺序是destination first,然后source 。因此,您将这些参数反转,并且此调用将引发运行时 API 错误,如果您进行了正确的错误检查(或在cuda-memcheck输出中可见),您可以观察到该错误。

修复这些错误后,qrf 调用实际上将返回零状态(无错误)。但是我们还没有完成(同样,正确的错误检查会让我们知道我们还没有完成。)

  1. 除了上述错误之外,您还犯了一些额外的尺寸错误。你的矩阵是 size 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 调用返回错误。

于 2015-12-18T17:32:51.470 回答