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函数调用时,然后在子内核启动时再次发生 至少发生在引擎盖下。