16

CUDA provides built-in vector data types like uint2, uint4 and so on. Are there any advantages to using these data types?

Let's assume that I have a tuple which consists of two values, A and B. One way to store them in memory is to allocate two arrays. The first array stores all the A values and the second array stores all the B values at indexes that correspond to the A values. Another way is to allocate one array of type uint2. Which one should I use? Which way is recommended? Does members of uint3 i.e x, y, z reside side by side in memory?

4

3 回答 3

6

这有点投机,但可能会增加@ArchaeaSoftware 的答案。

我主要熟悉 Compute Capability 2.0 (Fermi)。对于这种架构,我认为使用矢量化类型没有任何性能优势,除了 8 位和 16 位类型。

查看 char4 的声明:

struct __device_builtin__ __align__(4) char4
{
    signed char x, y, z, w;
};

类型对齐到 4 个字节。我不知道有什么__device_builtin__作用。也许它在编译器中触发了一些魔法......

float1,float2float3的声明看起来有点奇怪float4

struct __device_builtin__ float1
{
    float x;
};

__cuda_builtin_vector_align8(float2, float x; float y;);

struct __device_builtin__ float3
{
    float x, y, z;
};

struct __device_builtin__ __builtin_align__(16) float4
{
    float x, y, z, w;
};

float2得到某种形式的特殊待遇。float3是一个没有任何对齐的结构,并float4对齐到 16 个字节。我不知道该怎么做。

全局内存事务为 128 字节,与 128 字节对齐。事务总是一次执行一个完整的warp。当一个 warp 到达一个执行内存事务的函数时,比如从全局内存中加载 32 位,芯片将在那时执行为服务于 warp 中的所有 32 个线程所需的事务。因此,如果所有访问的 32 位值都在单个 128 字节行内,则只需要一个事务。如果值来自不同的 128 字节行,则执行多个 128 字节事务。对于每个事务,warp 会暂停大约 600 个周期,同时从内存中获取数据(除非它在 ​​L1 或 L2 缓存中)。

因此,我认为找出哪种方法提供最佳性能的关键是考虑哪种方法导致最少的 128 字节内存事务。

假设内置向量类型只是结构,其中一些具有特殊对齐方式,使用向量类型会导致值以交错方式存储在内存(结构数组)中。因此,如果 warp 正在加载x该点的所有值,其他值 ( y, z, w) 将因为 128 字节事务而被拉入 L1。当 warp 稍后尝试访问这些时,它们可能不再位于 L1 中,因此必须发出新的全局内存事务。此外,如果编译器能够发出更广泛的指令以同时读取更多值,以供将来使用,它将使用寄存器来存储加载点和使用点之间的值,这可能会增加寄存器的使用的内核。

另一方面,如果将值打包到数组结构中,则可以使用尽可能少的事务处理负载。因此,从x数组中读取时,只有x值被加载到 128 字节事务中。这可能会导致更少的事务、更少的对缓存的依赖以及计算和内存操作之间的更均匀分布。

于 2012-09-09T22:27:19.110 回答
4

我不相信 CUDA 中的内置元组 ([u]int[2|4], float[2|4], double[2]) 有任何内在优势;它们的存在主要是为了方便。您可以使用相同的布局定义自己的 C++ 类,编译器会有效地对它们进行操作。硬件确实具有本机 64 位和 128 位负载,因此您需要检查生成的微码以确定。

至于您应该使用 uint2 数组(结构数组或 AoS)还是两个 uint 数组(数组结构或 SoA),没有简单的答案 - 这取决于应用程序。对于方便大小的内置类型(2x32 位或 4x32 位),AoS 的优点是您只需要一个指针来加载/存储每个数据元素。SoA 需要多个基指针,或者每个元素至少需要多个偏移量和单独的加载/疼痛操作;但对于有时仅在元素子集上运行的工作负载,它可能会更快。

作为使用 AoS 获得良好效果的工作负载示例,请查看 nbody 样本(它使用 float4 来保存每个粒子的 XYZ+质量)。Black-Scholes 示例使用 SoA,大概是因为 float3 是一个不方便的元素大小。

于 2012-09-09T21:44:50.757 回答
3

另一个线程中有一些很好的信息与这里所说的许多主要结论相矛盾。

于 2016-08-15T17:15:26.320 回答