我试图理解矩阵转置如何从列与行中更快地读取。 (例子来自Professional CUDA C Programming)矩阵按行存储,即(0,1),(0,2),(0,3)......(1,1),(1,2)< / p>
__global__ void transposeNaiveCol(float *out, float *in, const int nx, const int ny) {
unsigned int ix = blockDim.x * blockIdx.x + threadIdx.x;
unsigned int iy = blockDim.y * blockIdx.y + threadIdx.y;
if (ix < nx && iy < ny) {
out[iy*nx + ix] = in[ix*ny + iy]; //
// out[ix*ny + iy] = in[iy*nx + ix]; // for by row
}
}
这是我不明白的:transposeNaiveCol()的负载吞吐量为642.33 GB / s,tranposeNaiveRow()的负载吞吐量为129.05 GB / s。作者说:
结果表明,获得了最高的负载吞吐量 缓存,跨读。在缓存读取的情况下,每个内存 请求使用128字节的高速缓存行进行服务。通过读取数据 columns使warp中的每个内存请求重放32次 (因为步幅是2048个数据元素),导致良好的延迟 隐藏在许多飞行中的全局内存读取,然后是优秀的L1 一旦将字节预先提取到L1缓存中,就会将缓存命中率。
我的问题: 我认为对齐/合并读取是理想的,但是在这里似乎跨步读取提高了性能。
答案 0 :(得分:5)
有效负载吞吐量并不是决定内核性能的唯一指标!具有完美合并负载的内核总是具有比等效的非合并内核更低的有效负载吞吐量,但单独没有说明其执行时间:最后, 真正重要的一个指标是内核完成时的挂钟时间,作者没有提及。
话虽这么说,内核通常分为两类:
矩阵转置具有非常低的计算强度,因此它受I / O限制,因此为了获得更好的性能,您应该尝试增加带宽使用。
为什么列的转置能更好地最大化带宽使用?
在行转置的情况下,读取被合并:每个warp提供一个128字节的事务,即每个线程4个字节。这128个字节放在缓存中,但从不重复使用,因此在这种情况下缓存实际上没用。
在列转置的情况下,读取不合并:每个warp获得32个128字节的事务,所有这些都将进入L1并将在接下来的31次重放中重复使用(假设它们没有被踢超出缓存)。对于非常高的有效负载吞吐量和最大的高速缓存使用率,这是非常低的负载效率。
当然,您可以通过简单地为每个线程请求更多数据(例如,通过为每个线程加载32 float
或8 float4
)或使用CUDA的预取功能,在行转置中获得相同的效果。