cuda - 来自设备的 cublas 矩阵求逆

标签 cuda cublas

我正在尝试从设备运行矩阵求逆。如果从主机调用,此逻辑工作正常。

编译行如下(Linux):

nvcc -ccbin g++ -arch=sm_35 -rdc=true simple-inv.cu -o simple-inv -lcublas_device -lcudadevrt

我收到以下警告,我似乎无法解决。 (我的GPU是Kepler,不知道为什么要链接Maxwell例程,我有Cuda 6.5-14):

nvlink warning : SM Arch ('sm_35') not found in '/usr/local/cuda/bin/../targets/x86_64-linux/lib/libcublas_device.a:maxwell_sm50_sgemm.o'

程序运行:

handle 0 n = 3
simple-inv.cu:63 Error [an illegal memory access was encountered]

测试程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>

#define PERR(call) \
  if (call) {\
   fprintf(stderr, "%s:%d Error [%s] on "#call"\n", __FILE__, __LINE__,\
      cudaGetErrorString(cudaGetLastError()));\
   exit(1);\
  }
#define ERRCHECK \
  if (cudaPeekAtLastError()) { \
    fprintf(stderr, "%s:%d Error [%s]\n", __FILE__, __LINE__,\
       cudaGetErrorString(cudaGetLastError()));\
    exit(1);\
  }

__global__ void
inv_kernel(float *a_i, float *c_o, int n)
{ 
  int p[3], info[1], batch;
  cublasHandle_t hdl;
  cublasStatus_t status = cublasCreate_v2(&hdl);
  printf("handle %d n = %d\n", status, n);

  info[0] = 0;
  batch = 1;
  float *a[] = {a_i};
  const float *aconst[] = {a_i};
  float *c[] = {c_o};
  // See
  // http://docs.nvidia.com/cuda/pdf/CUDA_Dynamic_Parallelism_Programming_Guide.pdf
  //http://stackoverflow.com/questions/27094612/cublas-matrix-inversion-from-device

  status = cublasSgetrfBatched(hdl, n, a, n, p, info, batch);
  __syncthreads();
  printf("rf %d info %d\n", status, info[0]);
  status = cublasSgetriBatched(hdl, n, aconst, n, p,
      c, n, info, batch);
  __syncthreads();
  printf("ri %d info %d\n", status, info[0]);

  cublasDestroy_v2(hdl);
  printf("done\n");
}
static void
run_inv(float *in, float *out, int n)
{
  float *a_d, *c_d;

  PERR(cudaMalloc(&a_d, n*n*sizeof(float)));
  PERR(cudaMalloc(&c_d, n*n*sizeof(float)));
  PERR(cudaMemcpy(a_d, in, n*n*sizeof(float), cudaMemcpyHostToDevice));

  inv_kernel<<<1, 1>>>(a_d, c_d, n);

  cudaDeviceSynchronize();
  ERRCHECK;

  PERR(cudaMemcpy(out, c_d, n*n*sizeof(float), cudaMemcpyDeviceToHost));
  PERR(cudaFree(a_d));
  PERR(cudaFree(c_d));
}

int
main(int argc, char **argv)
{
  float c[9];
  float a[] = {
    1,   2,   3,
    0,   4,   5,
    1,   0,   6 };

  run_inv(a, c, 3);
  return 0;
}

我已按照 http://docs.nvidia.com/cuda/cublas/index.html#device-api 上的指南进行操作2.1.9 节,但我怀疑我忽略了一些东西。

注意:于 11 月 24 日编辑以使用正确的指针输入。这仍然报告内核内部的非法内存访问。

最佳答案

注意:自 CUDA 10.0 起,从设备代码调用 cublas 函数的能力已从 CUDA 中移除。此答案中的描述仅适用于 CUDA 9.x 和之前的用法。参见 here .

关于 sm_50 的警告是良性的。这就是我所说的“在这种情况下可以安全地忽略它们”的方式。

关于您当前发布的代码,问题与动态并行文档中关于使用线程本地内存的描述有关here .

简而言之,父线程的本地内存在子内核启动中“超出范围”。虽然不是很明显,但来自设备代码的 cublas 调用正在(尝试)启动子内核。这意味着像这样的声明:

int p[3], info[1],

如果将这些指针(例如 pinfo)传递给子内核,将会出现问题。指针本身的数值不会被破坏,但它们不会指向子内核内存空间中任何“有意义”的东西。

有多种方法可以解决这个问题,但一个可能的解决方案是用来自“设备堆”的分配替换这种类型的任何堆栈/本地分配,这可以通过 in-kernel malloc 进行。 .

这是一个完整的代码/示例,似乎对我来说工作正常。对于给定样本矩阵的反转,输出似乎是正确的:

$ cat t605.cu
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>

#define PERR(call) \
  if (call) {\
   fprintf(stderr, "%s:%d Error [%s] on "#call"\n", __FILE__, __LINE__,\
      cudaGetErrorString(cudaGetLastError()));\
   exit(1);\
  }
#define ERRCHECK \
  if (cudaPeekAtLastError()) { \
    fprintf(stderr, "%s:%d Error [%s]\n", __FILE__, __LINE__,\
       cudaGetErrorString(cudaGetLastError()));\
    exit(1);\
  }

__global__ void
inv_kernel(float *a_i, float *c_o, int n)
{
  int *p = (int *)malloc(3*sizeof(int));
  int *info = (int *)malloc(sizeof(int));
  int batch;
  cublasHandle_t hdl;
  cublasStatus_t status = cublasCreate_v2(&hdl);
  printf("handle %d n = %d\n", status, n);

  info[0] = 0;
  batch = 1;
  float **a = (float **)malloc(sizeof(float *));
  *a = a_i;
  const float **aconst = (const float **)a;
  float **c = (float **)malloc(sizeof(float *));
  *c = c_o;
  // See
  // http://docs.nvidia.com/cuda/pdf/CUDA_Dynamic_Parallelism_Programming_Guide.pdf
  //http://stackoverflow.com/questions/27094612/cublas-matrix-inversion-from-device
  status = cublasSgetrfBatched(hdl, n, a, n, p, info, batch);
  __syncthreads();
  printf("rf %d info %d\n", status, info[0]);
  status = cublasSgetriBatched(hdl, n, aconst, n, p,
      c, n, info, batch);
  __syncthreads();
  printf("ri %d info %d\n", status, info[0]);
  cublasDestroy_v2(hdl);
  printf("done\n");
}
static void
run_inv(float *in, float *out, int n)
{
  float *a_d, *c_d;

  PERR(cudaMalloc(&a_d, n*n*sizeof(float)));
  PERR(cudaMalloc(&c_d, n*n*sizeof(float)));
  PERR(cudaMemcpy(a_d, in, n*n*sizeof(float), cudaMemcpyHostToDevice));

  inv_kernel<<<1, 1>>>(a_d, c_d, n);

  cudaDeviceSynchronize();
  ERRCHECK;

  PERR(cudaMemcpy(out, c_d, n*n*sizeof(float), cudaMemcpyDeviceToHost));
  PERR(cudaFree(a_d));
  PERR(cudaFree(c_d));
}

int
main(int argc, char **argv)
{
  float c[9];
  float a[] = {
    1,   2,   3,
    0,   4,   5,
    1,   0,   6 };

  run_inv(a, c, 3);
  for (int i = 0; i < 3; i++){
    for (int j = 0; j < 3; j++) printf("%f, ",c[(3*i)+j]);
    printf("\n");}

  return 0;
}
$ nvcc -arch=sm_35 -rdc=true -o t605 t605.cu -lcublas_device -lcudadevrt
nvlink warning : SM Arch ('sm_35') not found in '/shared/apps/cuda/CUDA-v6.5.14/bin/..//lib64/libcublas_device.a:maxwell_sgemm.asm.o'
nvlink warning : SM Arch ('sm_35') not found in '/shared/apps/cuda/CUDA-v6.5.14/bin/..//lib64/libcublas_device.a:maxwell_sm50_sgemm.o'
$ ./t605
handle 0 n = 3
rf 0 info 0
ri 0 info 0
done
1.090909, -0.545455, -0.090909,
0.227273, 0.136364, -0.227273,
-0.181818, 0.090909, 0.181818,
$

对于 CUDA 10.0 和更新版本的用户,我建议使用主机代码中的普通批处理 cublas 函数。特别是对于矩阵求逆,一种选择是使用 matinvBatched .

关于cuda - 来自设备的 cublas 矩阵求逆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27094612/

相关文章:

c++ - 与 cusparse 相比,cublas 异常缓慢

java - cublasSgemm与jcuda批量使用

python - 如何在 Numba cuda 中对字符串数组执行内核函数?

c++ - 用于矩阵加法的 Cuda 程序

cuda - 我在使用 CUDA 在 GPU 上复制字符时遇到问题

cublasStrsmBatched - 执行失败

cuda - CUDA 中的矩阵向​​量乘法 : benchmarking & performance

qt - CUDA 10 不支持高于 7 的 Gcc 版本 - Arch Linux 中的 Qt 错误

cuda - 寄存器溢出是否可能导致 CUDA_EXCEPTION_5,Warp Out-Of-Range Address 错误?

matrix - CUBLAS - 矩阵元素求幂可能吗?