将整个全局内存缓冲区多次复制到共享内存缓冲区

时间:2011-11-09 03:30:30

标签: cuda

我在全局内存中有一个缓冲区,我想在每个块的共享内存中复制,以加快我的只读访问速度。每个块中的每个线程将同时使用不同位置的整个缓冲区。

如何做到这一点?

我只在运行时知道缓冲区的大小:

__global__ void foo( int *globalMemArray, int N )
{
    extern __shared__ int s_array[];

    int idx = blockIdx.x * blockDim.x + threadIdx.x;

    if( idx < N )
    {

       ...?
    }
}

1 个答案:

答案 0 :(得分:4)

要做的第一点是共享内存限制为每个流多处理器(SM)最多16kb或48kb,具体取决于您使用的GPU及其配置方式,因此除非您的全局内存缓冲区非常很小,您将无法同时将所有内容加载到共享内存中。

要做的第二点是共享内存的内容只有与之关联的块的范围和生命周期。您的示例内核只有一个全局内存参数,这让我觉得您要么误解共享内存分配的内容可以保留超出填充它的块的生命周期,或者您打算写入块计算的结果返回到从中读取输入数据的相同全局存储器阵列。第一种可能性是错误的,第二种可能导致记忆竞争和不一致的结果。将共享内存视为一个小型的块范围L1缓存可能更好,它可以完全由程序员管理,而不是某种更快的全局内存版本。

有了这些点,一个内核加载了一个大输入数组的过多段,处理它们然后写了一些每个线程最终结果返回输入全局内存可能看起来像这样:

template <int blocksize>
__global__ void foo( int *globalMemArray, int *globalMemOutput, int N ) 
{ 
    __shared__ int s_array[blocksize]; 
    int npasses = (N / blocksize) + (((N % blocksize) > 0) ? 1 : 0);

    for(int pos = threadIdx.x; pos < (blocksize*npasses); pos += blocksize) { 
        if( pos < N ) { 
            s_array[threadIdx.x] = globalMemArray[pos];
        }
        __syncthreads(); 

        // Calculations using partial buffer contents
        .......

        __syncthreads(); 
    }

    // write final per thread result to output
    globalMemOutput[threadIdx.x + blockIdx.x*blockDim.x] = .....;
} 

在这种情况下,我已将共享内存数组大小指定为模板参数,因为实际上不需要在运行时动态分配共享内存数组大小,并且编译器在共享时执行优化的可能性更大内存数组大小在编译时是已知的(可能在最坏的情况下,可能在运行时完成不同内核实例之间的选择)。

CUDA SDK包含许多优秀的示例代码,这些代码演示了在内核中使用共享内存以提高内存读写性能的不同方法。矩阵转置,约简和三维有限差分方法示例都是共享内存使用的良好模型。每篇文章都有一篇很好的论文,讨论了代码中共享内存使用背后的优化策略。在了解它们的工作方式和原因之前,学习它们会得到很好的服务。