我正在努力理解合并全局记忆 假设我想将一组奇怪的浮点数加载到全局内存中。每个线程将处理一组3个浮点数。假设这些花车是A,B和C.
A0, B0, C0
A1, B1, C1
A2, B2, C2
..
A19, B19, C19
所以线程会抓住这样的数据:
Thread 0: A0, B0, C0
Thread 1: A1, B1, C1
Thread 2: A2, B2, C2
..
Thread 19: A19, B19, C19
第一种方法:
我可以加载3个数组:float A[20]; float B[20]; floatC[20];
我必须将cudaMemcpy()三次不同的时间加载到全局内存中。这种方法可能不会很好地融合。
第二种方法:
更好的方法是:
struct {float A, float B, float C} dataPt;
dataPt data[20];
我可以使用一个cudaMemcpy()加载数据,但我不确定内存访问是否会很好地合并。
第三种方法:
struct {float A, float B, float C, float padding} dataPt2;
dataPt2 data2[20];
或
struct __align__(16){float A, float B, float C} dataPt3;
dataPt3 data3[20];
我可以使用单个cudaMemcpy()将数据加载到全局内存,并且可以合并对数据的线程访问。 (以浪费的全球记忆为代价。)
1)第一种方法不会合并,因为每个线程可能需要3个总线周期才能加载输入数据
2)第二种方法将合并为许多线程,但是会有一些线程需要两个总线周期来获取输入数据。
3)第3种方法将合并所有线程。
这准确吗?第二个和第二个之间是否存在显着差异?第三种方法?有没有一种方法使用3个线程维度(threadIdx.x,threadIdx.y,threadIdx.z)?
答案 0 :(得分:2)
放大@talonmies的答案。 我们假设我们的内核看起来像这样:
__global__ void kern(float *a, float *b, float *c){
float local_a, local_b, local_c;
int idx = threadIdx.x + (blockDim.x * blockIdx.x);
local_a = a[idx];
local_b = b[idx];
local_c = c[idx];
}
忽略优化(这将导致空内核),并假设我们启动了1个32个线程的块:
kern<<<1, 32>>>(d_a, d_b, d_c);
然后我们在锁步中执行32个线程(1个warp)。这意味着每个线程将处理以下内核代码行:
local_a = a[idx];
在同一时间。合并负载(来自全局存储器)的定义是当warp加载一系列数据项时,这些数据项都在全局存储器中的单个128字节对齐边界内(对于CC 2.0设备)。具有100%带宽利用率的完美合并负载意味着每个线程在该128字节对齐区域内使用一个唯一的32位数量。如果线程零加载[0],则线程1加载[1]等,这可能是合并负载的典型示例。
因此,在第一种情况下,由于a []数组是连续且对齐的,并且[0..31]适合全局内存中的128字节对齐区域,因此我们得到了合并负载。线程0读取[0],线程1读取[1]等。
在第二种情况下,[0]与[1]不连续,此外元素a [0..31](均在同一代码行加载)不适合128字节全局记忆中的对齐序列。我将让你解析在你的第三种情况下发生的事情,但足以说明像第二种情况一样,元素a [0..31]不是连续的,也不包含在全局存储器中的单个128字节对齐区域内。虽然没有必要使数据项连续达到某种程度的合并,但是32线程扭曲的100%带宽利用率(“完美”)合并负载意味着每个线程使用唯一的32位项目,所有这些都是连续且包含在全局存储器中的单个128字节对齐序列中。
一个方便的心智模型是对比结构的Arrary(AoS)(对应于你的情况2和3)和一个数组结构(SoA),这基本上是你的第一个案例。 SoA通常比AoS提供更好的合并可能性。从nvidia webinar page您可能会发现this presentation有趣,特别是幻灯片11-22左右。
答案 1 :(得分:0)
“最佳做法指南”中的其他一些相关信息:
对于计算能力2.x的设备,要求可以是 很容易总结:一个线程的并发访问 warp将合并为多个等于该数字的事务 服务warp的所有线程所需的缓存行数。通过 默认情况下,所有访问都通过L1缓存,其为128字节行。 对于分散的访问模式,为了减少过度捕获,有时可以 仅在L2中缓存很有用,L2缓存较短的32字节段 (参见CUDA C编程指南)。
编译器标志:-Xptxas -dlcm=cg
将禁用L1缓存。即仅使用L2,用于合并不良的数据。