CUDA无效的设备符号错误

时间:2014-03-12 22:05:57

标签: cuda nvcc

下面的代码编译得很好。但是当我尝试运行它时,我得到了

GPUassert: invalid device symbol file.cu 114

当我评论由(!!!)标记的行时,错误不会出现。我的问题是导致这个错误的原因是因为它没有任何意义。

使用nvcc file.cu -arch compute_11

进行编译
#include "stdio.h"
#include <algorithm>
#include <ctime>

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
#define THREADS 64
#define BLOCKS 256
#define _dif (((1ll<<32)-121)/(THREADS*BLOCKS)+1)

#define HASH_SIZE 1024
#define ROUNDS 16
#define HASH_ROW (HASH_SIZE/ROUNDS)+(HASH_SIZE%ROUNDS==0?0:1)
#define HASH_COL 1000000000/HASH_SIZE


typedef unsigned long long ull;

inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
  if (code != cudaSuccess) 
  {
  //fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
  printf("GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
  if (abort) exit(code);
  }
}

__device__ unsigned int primes[1024]; 
//__device__ unsigned char primes[(1<<28)+1];
__device__ long long n = 1ll<<32; 
__device__ ull dev_base;
__device__ unsigned int dev_hash; 
__device__ unsigned int dev_index; 

time_t curtime;

__device__ int hashh(long long x) {
  return (x>>1)%1024;
}
// compute (x^e)%n
__device__ ull mulmod(ull x,ull e,ull n) {
ull ans = 1;
while(e>0) {
    if(e&1) ans = (ans*x)%n;
    x = (x*x)%n;
    e>>=1;
}
return ans;
}

// determine whether n is strong probable prime base a or not.
// n is ODD
__device__ int is_SPRP(ull a,ull n) {
  int d=0;
  ull t = n-1;
  while(t%2==0) {
      ++d;
      t>>=1;
  }
  ull x = mulmod(a,t,n);
  if(x==1) return 1; 
  for(int i=0;i<d;++i) {
      if(x==n-1) return 1;
      x=(x*x)%n;
  }
  return 0;
}


__device__ int prime(long long x) {
//unsigned long long b = 2;
//return is_SPRP(b,(unsigned long long)x);
return is_SPRP((unsigned long long)primes[(((long long)0xAFF7B4*x)>>7)%1024],(unsigned long long)x);
}

__global__ void find(unsigned int *out,unsigned int *c) {

unsigned int buff[HASH_ROW][256];
int local_c[HASH_ROW];
for(int i=0;i<HASH_ROW;++i) local_c[i]=0;

long long b = 121+(threadIdx.x+blockIdx.x*blockDim.x)*_dif;
long long e = b+_dif;
if(b%2==0) ++b;
for(long long i=b;i<e && i<n;i+=2) {
    if(i%3==0 || i%5==0 || i%7==0) continue;
    int hash_num = hashh(i)-(dev_hash*(HASH_ROW));
    if(0<=hash_num && hash_num<HASH_ROW) {
    if(prime(i)) continue;
    buff[hash_num][local_c[hash_num]++]=(unsigned int)i;
    if(local_c[hash_num]==256) {
        int start = atomicAdd(c+hash_num,local_c[hash_num]);
        if(start+local_c[hash_num]>=HASH_COL) return;

        unsigned int *out_offset = out+hash_num*(HASH_COL)*4;
        for(int i=0;i<local_c[hash_num];++i) out_offset[i+start]=buff[hash_num][i]; //(!!!)
        local_c[hash_num]=0;
    }
    }
}
for(int i=0;i<HASH_ROW;++i) {
  int start = atomicAdd(c+i,local_c[i]);
  if(start+local_c[i]>=HASH_COL) return;
  unsigned int *out_offset = out+i*(HASH_COL)*4;
  for(int j=0;j<local_c[i];++j) out_offset[j+start]=buff[i][j]; //(!!!)
}

}

int main(void) {
printf("HASH_ROW: %d\nHASH_COL: %d\nPRODUCT: %d\n",(int)HASH_ROW,(int)HASH_COL,(int)(HASH_ROW)*(HASH_COL));

ull *base_adr;
gpuErrchk(cudaGetSymbolAddress((void**)&base_adr,dev_base));
gpuErrchk(cudaMemset(base_adr,0,7));
gpuErrchk(cudaMemset(base_adr,0x02,1));
}

2 个答案:

答案 0 :(得分:7)

一个相当不寻常的错误。

失败的原因是:

  • 通过仅指定虚拟体系结构(-arch compute_11),您可以将PTX编译步骤推迟到运行时(即您强制执行JIT编译)
  • JIT-compile失败(在运行时)
  • JIT-compile(和链接)失败意味着无法正确建立设备符号
  • 由于设备符号出现问题,设备符号cudaGetSymbolAddress上的操作dev_base失败,并引发错误。

为什么JIT编译失败?您可以通过指定ptxas而不是-arch=sm_11来触发机器代码编译(运行-arch compute_11汇编程序)来查找自己。如果你这样做,你将得到这个结果:

ptxas error   : Entry function '_Z4findPjS_' uses too much local data (0x10100 bytes, 0x4000 max)

因此,即使您的代码没有调用find内核,它也必须成功编译才能拥有符号的理智设备环境。

为什么会出现编译错误?因为每个线程请求过多的本地内存。 cc 1.x devices are limited to 16KB local memory per thread,并且您的find内核要求的内容远远超过({超过64KB)。

当我最初在我的设备上尝试时,我使用的是具有更高限制(每个线程512KB)的cc2.0设备,因此JIT编译步骤成功。

一般来说,我建议同时指定虚拟架构和机器架构,这样做的简便方法是:

nvcc -arch=sm_11 ....

(对于cc1.1设备)

这个question/answer也可能是有意义的,nvcc manual有关于虚拟机与机器架构的更多细节,以及如何为每个架构指定编译阶段。

我相信当您在内核中注释掉那些特定行时错误消失的原因是,在注释掉这些行的情况下,编译器能够优化对这些本地内存区域的访问,并优化掉实例化本地内存。这允许JIT编译步骤成功完成,并且您的代码运行&#34;没有运行时错误&#34;。

您可以通过评论这些行来验证这一点,然后指定完整的编译(nvcc -arch=sm_11 ...),其中-arch--gpu-architecture的缩写。

答案 1 :(得分:0)

此错误通常意味着内核已针对错误的体系结构进行了编译。您需要find out what the compute capability of your GPU is,然后为该架构编译它。例如。如果您的GPU具有计算能力1.1,请使用-arch = sm_11进行编译。您还可以为多个体系结构构建可执行文件。