全局存储器驻留在设备存储器中,并且设备存储器通过32字节、64字节或128字节存储器事务进行访问。这些存储器事务必须被自然对齐:只有32字节、64字节或128字节的存储体,与这些存储体对齐的设备存储器(即首地址为这些尺寸其中之一的倍数)才能被存储器事务读或写。
当一个warp执行一条访问全局存储器的指令时,它合并在此warp内的工作项对存储器的访问,根据每个工作项所访问的字长以及跨工作项的存储器地址的分布,将这些访问合并为一个或多个存储器事务。通常来说,有越多必要的存储器事务就有越多未被使用的字传输,使得指令吞吐被缩减。比如,如果一个32字节的存储器事务为每个工作项的4字节访问所生成,那么吞吐量就除以8(由于实践中有许多因素影响代码性能,这不能作为一个绝对的标准)。
为了最大化全局存储器吞吐,要通过以下方式来最大化合并访问是很重要的:
- 遵循最优访问模式;
- 使用满足尺寸与对齐要求的数据类型;
- 在某些情况下对数据进行填充,如当访问一个二维数组时,如果二维数组的行、列不是满足对齐要求的倍数,那么在外围填充0或其他不影响计算结果的数据,使得对二维数组的访问能最优。
全局存储器指令支持大小为1字节、2字节、4字节、8字节或16字节数据的读写。任一对驻留在全局存储器中数据的访问(通过一个变量或一个指针)编译为一个全局存储器指令,当且仅当数据类型为1字节、2字节、4字节、8字节或16字节大小并且数据自然对齐(即数据访问地址是该尺寸的倍数)。
如果数据大小与对齐没有被满足,那么此访存会被编译为交错访问模式的多条指令,从而阻碍了指令被充分合并。因此,推荐使用满足此要求的数据类型来访问全局存储器。
能自动满足对齐要求的内建数据类型为char、uchar、short、ushort、int、uint、long、ulong、f loat、double
。
对于结构体数据类型,数据大小与对齐可以通过指定其对齐属性来指示编译器使用所指定的对齐要求——attribute((aligned(对齐字节数)))。
比如:
struct S{f loat x;f loat y;}_attribute_((aligned(8)));
用结构体S所定义的变量将至少满足8字节对齐。
读任一非对齐的8字节或16字节的数据会产生不正确的结果,因此必须小心维护这些数据类型变量或数组的起始地址。