CUDA无效的设备符号错误

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

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));
}
最佳答案
一个不常见的错误.

失败发生的原因是:

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

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

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

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

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

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

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

nvcc -arch=sm_11 ....

(对于cc1.1设备)

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

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

你可以通过注释这些行来验证这一点,然后指定一个完整的编译(nvcc -arch = sm_11 …),其中-arch是–gpu-architecture的缩写.

转载注明原文:CUDA无效的设备符号错误 - 代码日志