如何正确地将全局内存中的写入合并到全局内存中?

时间:2013-03-17 09:22:12

标签: cuda

请理解我,但我不懂英语。

我的计算环境

  • CPU:Intel Xeon x5690 3.46Ghz * 2EA
  • 操作系统:CentOS 5.8
  • VGA:Nvidia Geforce GTX580(CC为2.0)

我已经在CUDA C编程指南上阅读了有关“合并内存访问”的文档。 但我不能在我的案子中应用它们。

我有32x32块/网格和16x16线程/块。 这意味着如下代码。

dim3 grid(32, 32);
dim3 block(16,16);

kernel<<<grid, block>>>(...);

然后,我如何使用合并的内存访问?

我在下面的内核中使用了代码。

int i = blockIdx.x*16 + threadIdx.x;
int j = blockIdx.y*16 + threadIdx.y;

...

global_memory[i*512+j] = ...;

我使用常量512,因为线程总数是512x512个线程:它是grid_size x block_size。

但是,我从Visual Profiler中看到“全局内存存储效率低[平均9.7%,内核占计算量的100%]”。

Helper说使用合并的内存访问。 但是,我不知道应该使用内存的索引上下文。

有关详细代码的详细信息,请The result of an experiment different from CUDA Occupancy Calculator

1 个答案:

答案 0 :(得分:2)

在CUDA中合并内存加载和存储是一个非常简单的概念 - 同一warp 中的线程需要从内存中加载或存储适当对齐的连续单词。

CUDA中的warp大小为32,warp由同一块中的线程组成,排序使得threadIdx.{xyz}的x维度变化最快,y表示下一个最快,z表示最慢(在功能上,这与数组中的列主要排序相同)。

您发布的代码未实现合并内存存储,因为同一warp中的线程以512个字的间距存储,而不是在所需的32个连续字中。

改进合并的简单方法是按列主要顺序处理内存,所以:

int i = blockIdx.x*16 + threadIdx.x;
int j = blockIdx.y*16 + threadIdx.y;

...

global_memory[i+512*j] = ...;

在2D块和网格上采用更一般的方法,以你在问题中展示的精神实现合并将是这样的:

   tid_in_block = threadIdx.x + threadIdx.y * blockDim.x;
   bid_in_grid = blockIdx.x + blockIdx.y * gridDim.x;
   threads_per_block = blockDim.x * blockDim.y;

   tid_in_grid = tid_in_block + thread_per_block * bid_in_grid;

   global_memory[tid_in_grid] = ...;

最合适的解决方案将取决于您未描述的代码和数据的其他详细信息。