c++ CUDA:具有重叠边界的共享内存分配

tuwxkamq  于 2023-05-20  发布在  其他
关注(0)|答案(3)|浏览(111)

有没有一种简单的方法(google还没有提供……)从单个输入数组中分配每个块的共享内存区域,这样就可以有重叠?
简单的例子是字符串搜索;我想把输入文本切成小块,让每个块中的每个线程搜索从text[thread_id]开始的模式,但是希望分配给每个块的数据按照模式长度重叠,这样仍然可以找到跨越边界的匹配情况。
即分配给每个块上的共享内存的总内存大小为

(blocksize+patternlength)*sizeof(char)

我可能错过了一些简单的东西,目前正在通过CUDA指南潜水,但会感谢一些指导。
更新:我怀疑有些人误解了我的问题(或者我没有解释清楚)。
假设我有一个数据集QWERTYUIOP,我想搜索一个3个字符的匹配,我将数据集(任意)切成4个线程块; QWER TYUI OPxx
这很容易实现,但如果3个字符匹配实际上是在查找IOP,则算法会失败。
在这种情况下,我想要的是每个块都在共享内存中:

QWERTY TYUIOP OPxxxx

即,每个块被分配X1 M4 N1 X字符,因此不会发生存储器边界问题。
希望这能更好地解释事情。
因为@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);
}

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

voj3qocg

voj3qocg1#

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

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

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

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

uxhixvfz

uxhixvfz2#

不可以。共享内存是在一个块中的线程之间共享的,并且只能被分配给它的块访问。不能有可用于两个不同块的共享内存。
据我所知,共享内存实际上驻留在多处理器上,线程只能从它所运行的多处理器访问共享内存。这是一个物理限制。(我猜如果两个块驻留在一个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(其中透镜为您的blocksize + patternlength
  • 内核假设gridDim.x * blockDim.x = lenT(与版本1相同)
  • 我们可以并行复制到共享内存中(如果有足够的线程,就不需要for循环)
mnemlml8

mnemlml83#

重叠共享内存并不好,线程每次想要访问共享内存中的同一地址时都必须同步(尽管在架构>= 2.0中,这已经得到了缓解)。
我想到的最简单的想法是复制你想要重叠的文本部分。
而不是从全局内存中读取精确的块:
AAAA BBBB CCCC DDDD EEEE
重叠读取:
AAAA BBBB CCCCCCCCDDDD EEEEE

相关问题