我正在尝试从设备运行矩阵求逆。如果从主机调用,此逻辑工作正常。
编译行如下(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编辑使用正确的指针输入。这仍然会报告内核中的非法内存访问。
答案 0 :(得分:4)
关于sm_50的警告是良性的。这是我的说法,“在这种情况下可以安全地忽略它们。”
关于您当前发布的代码,问题与动态并行度文档中有关使用线程局部内存here的内容有关。
简而言之,父线程的本地内存在子内核启动时“超出范围”。虽然它并不完全明显,但是来自设备代码的cublas调用(尝试)启动子内核。这意味着这样的声明:
int p[3], info[1],
如果将这些指针(例如p
,info
)传递给子内核,将会出现问题。指针本身的数值不会被破坏,但它们不会指向子内核的内存空间中任何“有意义的”。
有多种方法可以解决这个问题,但一种可能的解决方案是用“设备堆”中的分配替换此类型的任何堆栈/本地分配,可以通过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,
$
答案 1 :(得分:0)
你运行的某些CUDA功能是否只有不同的架构支持(即使文档中说的所有内容都是。如果我使用-arch=sm_50
进行编译,我不会收到编译器警告。我不知道有一个支持sm_50的设备来测试......
此外,这些警告看起来像某些功能asm不适用于您的架构,因此它链接到不同的架构asm,您的设备不支持,因此您会遇到一些奇怪的错误。我认为你应该让这些nvidia开发人员更了解他们的编译器正在做什么。
我可以访问支持Compute 3.5的设备,但遗憾的是只能使用CUDA v 6.0并使用您的示例(稍微修复,编译(const float *) - &gt;(浮点*)第42行)我不知道得到任何编译警告(尽管结果可悲相同)。
同样如评论中所述:
(float**)a_i
不会使a_i成为类型(float **)。你应该拿地址: &安培; A_I
更改这些并没有帮助解决问题,但这些是您可以寻求探索的一些指示。