CUDA程序在sm_35开普勒GPU上提供cudaErrorIllegalAddress,但在其他GPU上运行良好
我的程序有一个很奇怪的问题。基本上我是在矩阵的一部分上进行矩阵乘法。该程序显然在大多数卡片上运行良好,但在sm_35开普勒(=GK110)卡片上崩溃 最初的程序是用PyCUDA编写的,但后来我设法将其归结为以下用C编写的最小示例:CUDA程序在sm_35开普勒GPU上提供cudaErrorIllegalAddress,但在其他GPU上运行良好,c,cuda,pycuda,cublas,C,Cuda,Pycuda,Cublas,我的程序有一个很奇怪的问题。基本上我是在矩阵的一部分上进行矩阵乘法。该程序显然在大多数卡片上运行良好,但在sm_35开普勒(=GK110)卡片上崩溃 最初的程序是用PyCUDA编写的,但后来我设法将其归结为以下用C编写的最小示例: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <cuda.h> #include <cuda_runtime.h> #
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
int main(int argc, char **argv)
{
cudaError_t status;
cublasStatus_t status_blas;
CUresult status_drv;
float *A = 0;
float *B = 0;
float *C = 0;
float alpha = 1.0f;
float beta = 0.0f;
float *oldA, *oldB, *oldC;
cublasHandle_t handle;
int n = 131;
int m = 2483;
int k = 3;
int i;
CUcontext ctx;
cuInit(0);
status_drv = cuCtxCreate(&ctx, 0, 0);
if (status_drv != CUDA_SUCCESS) {
fprintf(stderr, "!!!! Context creation error: %d\n", status);
return EXIT_FAILURE;
}
status_blas = cublasCreate(&handle);
if (status_blas != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLAS initialization error\n");
return EXIT_FAILURE;
}
for (i = 0; i < 5; ++i) {
printf("Iteration %d\n", i);
if (cudaMalloc((void **)&B, m * k * sizeof(B[0])) != cudaSuccess) {
fprintf(stderr, "!!!! allocation error (allocate B)\n");
return EXIT_FAILURE;
}
if (cudaMalloc((void **)&C, m * m * sizeof(C[0])) != cudaSuccess) {
fprintf(stderr, "!!!! allocation error (allocate C)\n");
return EXIT_FAILURE;
}
if (cudaMalloc((void **)&A, n * m * sizeof(A[0])) != cudaSuccess) {
fprintf(stderr, "!!!! allocation error (allocate A)\n");
return EXIT_FAILURE;
}
int s = 3;
float * A_slice = A + 128*m;
status_blas = cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, m, m, s,
&alpha, A_slice, m, B, k, &beta, C, m);
if (status_blas != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! kernel execution error.\n");
return EXIT_FAILURE;
}
if (i == 0) {
oldA = A;
oldB = B;
oldC = C;
} else if (i == 1) {
status = cudaFree(oldA);
if (status != cudaSuccess) {
fprintf(stderr, "!!!! allocation error (free A, %d)\n", status);
return EXIT_FAILURE;
}
if (cudaFree(oldB) != cudaSuccess) {
fprintf(stderr, "!!!! allocation error (free B)\n");
return EXIT_FAILURE;
}
if (cudaFree(oldC) != cudaSuccess) {
fprintf(stderr, "!!!! allocation error (free C)\n");
return EXIT_FAILURE;
}
}
}
cublasDestroy(handle);
cuCtxDestroy(ctx);
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv)
{
错误状态;
古巴国家地位;
治疗结果状态\u drv;
浮点数*A=0;
浮点数*B=0;
浮点数*C=0;
浮动α=1.0f;
浮动β=0.0f;
浮动*oldA、*oldB、*oldC;
立方手柄;
int n=131;
int m=2483;
int k=3;
int i;
CUcontext ctx;
cuInit(0);
状态_drv=cuCtxCreate(&ctx,0,0);
if(状态=CUDA\U成功){
fprintf(stderr,“!!!!上下文创建错误:%d\n”,状态);
返回退出失败;
}
状态_blas=cublasCreate(&handle);
如果(状态为blas!=CUBLAS状态为SUCCESS){
fprintf(stderr,“!!!!CUBLAS初始化错误\n”);
返回退出失败;
}
对于(i=0;i<5;++i){
printf(“迭代%d\n”,i);
if(cudamaloc((void**)和B,m*k*sizeof(B[0])!=cudaSuccess){
fprintf(stderr,“!!!!分配错误(分配B)\n”);
返回退出失败;
}
if(cudamaloc((void**)和C,m*m*sizeof(C[0])!=cudaSuccess){
fprintf(stderr,“!!!!分配错误(分配C)\n”);
返回退出失败;
}
if(cudamaloc((void**)和A,n*m*sizeof(A[0])!=cudaSuccess){
fprintf(stderr,“!!!!分配错误(分配A)\n”);
返回退出失败;
}
int s=3;
浮动*A_切片=A+128*m;
状态=cubllassemm(手柄,CUBLAS_OP_N,CUBLAS_OP_N,m,m,s,
&α,A_切片,m,B,k和β,C,m);
如果(状态为blas!=CUBLAS状态为SUCCESS){
fprintf(stderr,“!!!!内核执行错误。\n”);
返回退出失败;
}
如果(i==0){
oldA=A;
oldB=B;
oldC=C;
}else如果(i==1){
状态=cudaFree(oldA);
如果(状态!=cudaSuccess){
fprintf(stderr,“!!!!分配错误(自由A,%d)\n)”,状态;
返回退出失败;
}
if(cudaFree(oldB)!=cudaSuccess){
fprintf(stderr,“!!!!分配错误(免费B)\n”);
返回退出失败;
}
if(cudaFree(oldC)!=cudaSuccess){
fprintf(stderr,“!!!!分配错误(免费C)\n”);
返回退出失败;
}
}
}
立方体(把手);
cuCtxDestroy(ctx);
返回0;
}
我只在for循环的第二次迭代中释放内存,以模拟原始python程序的行为。当程序试图释放“A”时,它将在for循环的第二次迭代中崩溃,cudaFree返回cudaErrorIllegalAddress错误
具体地说,在以下卡片上进行了试验:
- NVS 5400M->无问题
- GTX560Ti->无问题
- 特斯拉S2050->无问题
- 未知的sm_30卡(见本文评论)->无问题
- K40c->碰撞
- GTX 780->碰撞
- K20m->碰撞
- malloc调用的顺序很重要。如果我先分配A再分配B,一切都会好起来
- 数值常数有点重要。对于某些值(例如n=30),不会发生崩溃,而对于其他值,则会发生崩溃
- free/malloc调用的顺序很重要。如果我在分配内存的同一个迭代中释放内存,一切都会正常工作
编辑:正如评论中所指出的,显然它只能在sm_35(即GK110卡)上运行,但在sm_30开普勒卡上运行良好。这个问题应该在CUDA 6.5产品发布包中解决,现在可以从下载。您发布的代码实际上不会编译。驱动程序API和CUBLAS中的枚举类型不可交换。它在我的机器上使用
nvcc test.c-o test-lcublas-lcuda
编译得很好。您遇到了什么错误?啊,现在我明白了,我检查了cuCtxCreate
调用CUBLAS\u STATUS\u SUCCESS
。我犯了愚蠢的错误。但是在本例中,这没关系,因为驱动程序API和CUBLAS都将“0”定义为“调用成功”值。我会修正上面的代码正如我所说的,Cubrasstatus_t、CUresult和cudaError_t不是同一类型,不能互换。在我修复了这个问题之后,代码在sm_30开普勒系统上运行时没有出现错误