包含在类中的CUDA共享内存指向同一个内存

时间:2015-10-26 12:13:03

标签: templates cuda

我试图在模板化的类中的CUDA内核中分配共享内存:

template<typename T, int Size>
struct SharedArray {

    __device__ T* operator()(){
        __shared__ T x[Size];
        return x;
    }
};

这样可以使用两次相同类型和大小的共享内存。但是当我尝试获得两次具有相同类型和大小的共享内存时,第二个共享内存指向第一个:

__global__
void test() {

    // Shared array
    SharedArray<int, 5> sharedArray;
    int* x0 = sharedArray();
    int* y0 = sharedArray();
    x0[0] = 1;
    y0[0] = 0;
    printf("%i %i\n\n", x0[0], y0[0]);
    // Prints:
    // 0 0
}

一种解决方案是在每次调用共享内存类时添加一个id,如:

template<int ID, typename T, int Size>
struct StaticSharedArrayWithID {

    __device__ static T* shared(){
        __shared__ T x[Size];
        return x;
    }   
};

但是我必须提供一些提供非常丑陋的用户界面的计数器:

__global__
void test() {

    int& x1 = StaticSharedArrayWithID<__COUNTER__, int, 5>::shared();
    int& y1 = StaticSharedArrayWithID<__COUNTER__, int, 5>::shared();
    x1[0] = 1;
    y1[0] = 0;
    printf("%i %i\n\n", x1[0], y1[0]);
    // Prints:
    // 1 0
}

有没有人有想法摆脱用户界面中的__COUNTER__宏?隐藏它是可以的。

1 个答案:

答案 0 :(得分:4)

原因是默认情况下__shared__个变量为static。同一函数的相同实例引用相同的变量。这种行为的最初原因是因为编译器无法扣除何时可以回收内存。变量static使其与内核一样长。

副作用是,如果你有两次相同的函数,它在程序中有两个位置 - 你会得到相同的结果。事实上,当你在多个CUDA线程在同一个地方调用你的函数时,这是你所期望的,不是吗?

没有干净的方法来动态分配共享内存。在我的项目中,我通过自己的共享内存管理器(前面的丑陋指针算法,小心!)来完成它。:

typedef unsigned char byte;

/*
  Simple shared memory manager.
    With any luck if invoked with constant parameters this will not take up any register whatsoever
    Must be called uniformly by whole block which is going to use these
    sSize - amount of preallocated memory
*/
template <size_t sSize>
class SharedMemoryManager {
private:
    byte* shArray;
    byte* head;
public:

    __device__ SharedMemoryManager() {
        __shared__ byte arr[sSize];
        shArray=arr;
        head=arr;
    }

    __device__  void reset() {
        head=shArray;
    }

    __device__  byte* getHead() {return head;}
    __device__  void setHead(byte* newHead) {head=newHead;}

    template <typename T>
    __device__  T* alloc(size_t count) {
      size_t addr = head;
      size_t alignment = __alignof(T); //assuming alignment is power of 2
      addr = ((addr-1) | (alignment-1)) +1; //round up to match the alignment requirement
      head = (byte*)(addr);
      T* var = (T*)(head);
      head+=sizeof(T)*size;
      return allocAt<T>(head,count);
    }

template <typename T>
    __device__  T& alloc() {
      return *alloc<T>(1);
    }

};

当您知道可以回收共享内存时,可以使用getHead / setHead来回收共享内存,但只能以堆栈方式回收。

当CUDA不是你的目标时,这种方法应该很容易在非共享内存上进行抽象。

然后你应该写:

__global__
 void test() {
   SharedMemoryManager shMem<1024>();

   int& xValue = shMem.alloc<int>();
   int& yValue = shMem.alloc<int>();
   int* xArray = shMem.alloc<int>(5);
   int* yArray = shMem.alloc<int>(5);

   xArray[0] = 1;
   yArray[0] = 0;
   printf("%i %i\n\n", xArray[0], yArray[0]);
   __syncthreads();
   shMem.reset(); //memory reclaimed
   ... 
}