CUDA:具有重叠边框的共享内存分配

时间:2011-04-06 14:35:18

标签: cuda

是否有一种简单的方法(谷歌尚未提供...)从单个输入数组分配每块共享内存区域,以便可能存在重叠?

简单的例子是字符串搜索;看到我想要输入文本,让每个块中的每个线程搜索从text [thread_id]开始的模式,但是希望分配给每个块的数据按模式长度重叠,以便匹配跨越边界的情况是还是找到了。

即,每个块上分配给共享内存的总内存大小为

(blocksize+patternlength)*sizeof(char)

我可能遗漏了一些简单的东西,目前我正在通过CUDA指南,但我会很感激一些指导。

更新:我怀疑有些人误解了我的问题(或者我误解了)。

假设我有一个数据集QWERTYUIOP,我想搜索一个3个字符的匹配,并且我将数据集(任意)切成4个每个线程块; QWER TYUI OPxx

这很容易实现,但如果3个字符匹配实际上正在寻找IOP,则算法会失败。

在这种情况下,我想要的是每个块在共享内存中的位置:

QWERTY TYUIOP OPxxxx

即为每个块分配块大小+ patternlength-1字符,因此不会出现内存边界问题。

希望能更好地解释事情。

由于@jmilloy持续......:P

//VERSION 1: Simple
__global__ void gpuSearchSimple(char *T, int lenT, char *P, int lenP, int *pFound)
{
  int startIndex = blockDim.x*blockIdx.x + threadIdx.x;
    int fMatch = 1;
    for (int i=0; i < lenP; i++)
    {
      if (T[startIndex+i] != P[i]) fMatch = 0;
    }
    if (fMatch) atomicMin(pFound, startIndex);
}
//VERSION 2: Texture
__global__ void gpuSearchTexture(int lenT, int lenP, int *pFound)
{
  int startIndex = blockDim.x*blockIdx.x + threadIdx.x;
    int fMatch = 1;
    for (int i=0; i < lenP; i++)
    {
      if (tex1Dfetch(texT,startIndex+i) != tex1Dfetch(texP,i)) fMatch = 0;
    }
    if (fMatch) atomicMin(pFound, startIndex);
}
//Version 3: Shared
__global__ void gpuSearchTexSha(int lenT, int lenP, int *pFound)
{
  extern __shared__ char shaP[];
  for (int i=0;threadIdx.x+i<lenP; i+=blockDim.x){
    shaP[threadIdx.x+i]= tex1Dfetch(texP,threadIdx.x+i);
  }
  __syncthreads();

  //At this point shaP is populated with the pattern
  int startIndex = blockDim.x*blockIdx.x + threadIdx.x;
    // only continue if an earlier instance hasn't already been found
    int fMatch = 1;
    for (int i=0; i < lenP; i++)
    {
      if (tex1Dfetch(texT,startIndex+i) != shaP[i]) fMatch = 0;
    }
    if (fMatch) atomicMin(pFound, startIndex);
}

我想要做的是将文本放入共享内存块,如问题的其余部分所述,而不是将文本保留在纹理内存中以用于更高版本。

3 个答案:

答案 0 :(得分:2)

我不确定这个问题是否有意义。您可以在运行时动态调整共享分配内存的大小,如下所示:

__global__ void kernel()
{
    extern __shared__ int buffer[];
    ....
}

kernel<<< gridsize, blocksize, buffersize >>>();

但是内核开头的缓冲区内容是未定义的。您必须在内核中设计一个方案,以便从全局内存加载您想要的重叠,以确保您的模式匹配可以按照您的意愿工作。

答案 1 :(得分:1)

重叠共享内存不好,线程每次想要访问共享内存中的相同地址时都必须进行同步(尽管在架构&gt; = 2.0中已经减轻了这一点)。

我想到的最简单的想法是复制你想要重叠的文本部分。

而不是从精确的chuncks中读取全局内存:

  

AAAA BBBB CCCC DDDD EEEE

重读:

  

AAAA BBBB CCCC CCCC DDDD EEEEE

答案 2 :(得分:1)

没有。共享内存在块中的线程之间共享,并且只能由分配给它的块访问。您不能拥有可用于两个不同块的共享内存。

据我所知,共享内存实际上驻留在多处理器上,而一个线程只能从运行它的多处理器访问共享内存。所以这是一个物理限制。 (我猜如果两个块驻留在一个mp上,一个块的线程可能无法预测地访问分配给另一个块的共享内存)。

请记住,您需要将数据从全局内存显式复制到共享内存。将字符串的重叠区域复制到非重叠的共享内存是一件简单的事情。

我认为在您需要的地方获取数据是开发CUDA程序所需的大部分工作。我的指导是你从一个解决问题的版本开始,而不首先使用任何共享内存。为了实现这一点,您将解决重叠问题,并且共享内存实现将很容易!


编辑2
答案被标记为正确后

__global__ void gpuSearchTexSha(int lenT, int lenP, int *pFound)
{
    extern __shared__ char* shared;

    char* shaP = &shared[0];
    char* shaT = &shared[lenP];

    //copy pattern into shaP in parallel
    if(threadIdx.x < lenP)
        shaP[threadIdx.x] = tex1Dfetch(texP,threadIdx.x);

    //determine texT start and length for this block
    blockStartIndex = blockIdx.x * gridDim.x/lenT;
    lenS = gridDim.x/lenT + lenP - 1;

    //copy text into shaT in parallel
    shaT[threadIdx.x] = tex1Dfetch(texT,blockStartIndex + threadIdx.x);
    if(threadIdx.x < lenP)
        shaP[blockDim.x + threadIdx.x] = text1Dfetch(texT,blockStartIndex + blockDim.x + threadIdx.x)

    __syncthreads();

    //We have one pattern in shaP for each thread in the block
    //We have the necessary portion of the text (with overlaps) in shaT

    int fMatch = 1;
    for (int i=0; i < lenP; i++)
    {
        if (shaT[threadIdx.x+i] != shaP[i]) fMatch = 0;
    }
    if (fMatch) atomicMin(pFound, blockStartIndex + threadIdx.x);
}

主要说明:

  • 我们每个块只需要共享内存中的一个模式副本 - 它们都可以使用它
  • 每个块所需的共享内存为lenP + lenS(其中lenS是您的blocksize + patternlength
  • 内核假定gridDim.x * blockDim.x = lenT(与版本1相同)
  • 我们可以并行复制到共享内存中(如果你有足够的线程,则不需要for循环)