Cuda 器件的立方矩阵求逆

Cuda 器件的立方矩阵求逆,cuda,cublas,Cuda,Cublas,我正试着从设备上进行矩阵求逆。如果从主机调用,此逻辑工作正常 编译行如下所示: nvcc -ccbin g++ -arch=sm_35 -rdc=true simple-inv.cu -o simple-inv -lcublas_device -lcudadevrt 我得到以下警告,我似乎无法解决。我的GPU是开普勒。我不知道为什么它试图链接到Maxwell例程。我有Cuda 6.5-14: nvlink warning : SM Arch ('sm_35') not found in '/u

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

编译行如下所示:

nvcc -ccbin g++ -arch=sm_35 -rdc=true simple-inv.cu -o simple-inv -lcublas_device -lcudadevrt
我得到以下警告,我似乎无法解决。我的GPU是开普勒。我不知道为什么它试图链接到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;
}
我遵循了第2.1.9节的指南,但我怀疑我忽略了什么


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

可能是因为您正在运行的某些CUDA功能仅受不同体系结构的支持,即使文档中说所有使用的都是。如果使用-arch=sm_50编译,则不会收到编译器警告。但是我没有一个支持sm_50的设备来测试

此外,这些警告看起来像是某些功能asm不适用于您的体系结构,因此它链接到了不同的体系结构asm,而您的设备不支持该体系结构asm,因此您会遇到一些奇怪的错误。我认为你应该采取这种nvidia开发谁更了解他们的编译器正在做什么

我可以访问Compute 3.5功能的设备,但不幸的是,只有使用CUDA v 6.0,并使用您的示例,在第42行编译const float*->float*,但我没有得到任何相同的编译结果

还如评论中所述:

(float**)a_i 
不是在做一个浮球**类型的球。您应该使用以下地址: &阿尤伊


更改这些并没有帮助解决问题,但您可以查看一些指针。

注意:从CUDA 10.0起,CUDA已取消从设备代码调用cublas函数的功能。本答案中的描述仅适用于CUDA 9.x及之前版本。看

关于sm_50的警告是善意的。这是我的说法,在这种情况下,可以安全地忽略它们

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

简而言之,在子内核启动中,父线程的本地内存超出范围。虽然不完全清楚,但是来自设备代码的cublas调用正试图启动子内核。这意味着这样的声明:

int p[3], info[1],
如果将这些指针(例如p、info)传递给子内核,则会出现问题。指针本身的数值不会被破坏,但它们不会指向子内核内存空间中任何有意义的内容

有多种方法可以解决此问题,但一种可能的解决方案是用设备堆中的分配来替换任何此类堆栈/本地分配,这些分配可以通过

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

$ 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,
$

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

您发布的代码中的第63行是空白。代码中发生的错误的具体位置?设备同步期间的第64行。我必须张贴和旧的输出。我怀疑在调用cublasgetrfbatched.float**a_时,我看起来很可疑。你的意思是传递a_i的地址而不是它的值吗?@VAndrei:是的,这是可能的,你的评论与问题完全无关。@Bob:你链接到的代码和你的代码是不同的,不同的是你有一个非法的施法*a[]={a_i};cublasSgetrfBatched…,a。。。。和cublasSgetrfBatched…,float**a_i。。。不等价,如果你认为它们是,那么你需要修改C++中指针的理论。对,我的坏。当我用Smi50编译时,我得到PTXAS信息:“设备函数Max RigReCalt”是beta特性。另一个警告消失了,谢谢。这对我有用。我最初分配了p和info变量,但没有意识到我还需要分配a、acost和c变量。在阅读本地内存参考部分后,这是有意义的。我可以想象n被分配到全局内存堆,因为它是内核调用参数的一部分。handle变量可能不适用。其他参数(如n、batch等)按值传递。通过值传递的参数没有引用回调用环境。这是C/C++的特点,不是唯一的CUDA概念。事实上,甚至指针都是按值传递的。但是当这些指针值在子内核中被取消引用时,坏事情就会发生。对于非指针参数,在子内核中不进行这样的去引用,并且一切正常。事实上,这个传递值实际上发生在cublas函数调用时,然后在子内核启动时再次发生 至少发生在引擎盖下。