Cuda 实现FDTD方程时的内存合并

Cuda 实现FDTD方程时的内存合并,cuda,Cuda,我试图在GPU上实现FDTD方程。我最初 实现了使用全局内存的内核。记忆 合并并没有那么好。因此,我实现了另一个内核 它使用共享内存加载值。我正在网格上工作 共1024x1024个 代码如下 __global__ void update_Hx(float *Hx, float *Ez, float *coef1, float* coef2){ int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y +

我试图在GPU上实现FDTD方程。我最初 实现了使用全局内存的内核。记忆 合并并没有那么好。因此,我实现了另一个内核 它使用共享内存加载值。我正在网格上工作 共1024x1024个

代码如下

__global__ void update_Hx(float *Hx, float *Ez, float *coef1, float* coef2){
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;
    __shared__ float  Ez_shared[BLOCKSIZE_HX][BLOCKSIZE_HY + 1];
    /*int top = offset + x_index_dim;*/
    if(threadIdx.y == (blockDim.y - 1)){
        Ez_shared[threadIdx.x][threadIdx.y] = Ez[offset];
        Ez_shared[threadIdx.x][threadIdx.y + 1] = Ez[offset + x_index_dim];
   }
    else{
        Ez_shared[threadIdx.x][threadIdx.y] = Ez[offset];
    }
}
常数
BLOCKSIZE\u HX
=
16
BLOCKSIZE\u HY
=
16

当我运行VisualProfiler时,它仍然表示内存没有合并

编辑: 我使用GT 520图形卡,cuda计算能力为2.1。 My Global L2 transactions/Access=
7.5
32768
行的执行
Ez_共享[threadIdx.x][threadIdx.y]=Ez[offset]

全局内存加载效率
50%

全局内存加载效率
=
100*gld\u请求的吞吐量/gld\u吞吐量

虽然我的线程正在查看16个连续的值,但我无法理解为什么会有这么多内存访问。有人能指出我做错了什么吗


编辑:谢谢您的帮助。

您的内存访问模式是这里的问题。您只能获得50%的效率(对于L1和L2),因为您正在访问16个浮点的连续区域,即64字节,但L1事务大小为128字节。这意味着,对于每64个请求字节,必须将128个字节加载到L1(因此也加载到L2)

您还存在共享内存库冲突问题,但这目前不会对全局内存加载效率产生负面影响


您可以通过几种方式解决负载效率问题。最简单的方法是将x尺寸块大小更改为32。如果这不是一个选项,您可以更改全局内存数据布局,使每个连续的块IDX.y([0,1]、[2,3]等)值映射到一个连续内存块。如果这不是一个选项,并且您必须只加载一次全局数据,那么您可以使用非缓存的全局内存加载绕过L1-这会有所帮助,因为L2使用32字节事务,因此您的64字节将在两个L2事务中加载,而不会产生开销。

您的内存访问模式就是这里的问题所在。您只能获得50%的效率(对于L1和L2),因为您正在访问16个浮点的连续区域,即64字节,但L1事务大小为128字节。这意味着,对于每64个请求字节,必须将128个字节加载到L1(因此也加载到L2)

您还存在共享内存库冲突问题,但这目前不会对全局内存加载效率产生负面影响


您可以通过几种方式解决负载效率问题。最简单的方法是将x尺寸块大小更改为32。如果这不是一个选项,您可以更改全局内存数据布局,使每个连续的块IDX.y([0,1]、[2,3]等)值映射到一个连续内存块。如果这不是一个选项,并且您必须只加载一次全局数据,那么您可以使用非缓存的全局内存加载绕过L1-这会有所帮助,因为L2使用32字节事务,因此您的64字节将加载到两个L2事务中,而不会产生开销。

请提供完整的示例。您提供的源代码中未定义x_index_dim。启动内核的网格和块大小是多少?您应该更改共享内存的定义和使用情况。您还应该重写if语句<代码>\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu共享[BLOCKSIZE\uhy+1][BLOCKSIZE\uhx]仅是一条评论,可能无法完全回答您的问题。在本页中,描述了一种避免使用
if
语句的解决方案,实现了一种通过BS_X*BS_Y线程填充(BS_X+1)*(BS_Y+1)共享内存矩阵的方法(另请参见相关讨论)。正如@RoBiK所说,一个问题是线程首先在X维中分组在一起(当机器将线程组织为扭曲时)。因此,您希望引用内存元素的数据访问的顺序为
data[z][y][x]
而不是
data[x][y][z]
@RoBiK我之前更改了顺序,并对探查器进行了rand。我仍然存在相同的问题。请提供完整的示例。您提供的源代码中没有定义x_index_dim。您启动内核的网格和块大小是什么?您应该更改共享内存定义和使用情况。此外,您还应该重写if语句t、
\uuuuu shared\uuuuuufloat Ez\u shared[BLOCKSIZE_HY+1][BLOCKSIZE_HX];
只是一个可能无法完全回答您问题的注释。在页面中,介绍了一种解决方案,它避免使用
if
语句,实现了一种通过BS_X*BS_Y线程填充(BS_X+1)*(BS_Y+1)共享内存矩阵的方法(另请参见关于的相关讨论)。正如@RoBiK所说,一个问题是线程首先在x维中分组(当机器将线程组织为扭曲时)。因此,您希望引用内存元素的数据访问的顺序为
data[z][y][x]
而不是
data[x][y][z]
@RoBiK我之前已经更改了顺序,并使用了rand探查器。我仍然有同样的问题。更改xdimension有帮助。但是我在哪里会有银行冲突。你是说将
EZ\u共享[BLOCKSIZE\u HX][BLOCKSIZE\u HY]
更改为
EZ\u共享[BLOCKSIZE\u HY][BLOCKSIZE\u HX]
。我已经这样做了。我感到惊讶的是,共享内存的代码比直接从全局内存访问所有值的代码表现得更糟糕。直接从全局内存访问内核需要3.259毫秒,而使用共享内存执行一次需要4.139毫秒。使用从全局内存直接访问时使用的块大小是埃默里是
256x1
@catchmrbharath这一切都取决于你用它做什么