使用CUDA矢量类型是否有优势?

使用CUDA矢量类型是否有优势?,cuda,abstract-data-type,Cuda,Abstract Data Type,CUDA提供内置向量数据类型,如uint2、uint4等。使用这些数据类型有什么好处吗 假设我有一个元组,它由两个值a和B组成。将它们存储在内存中的一种方法是分配两个数组。第一个数组存储所有A值,第二个数组在与A值对应的索引处存储所有B值。另一种方法是分配一个类型为uint2的数组。我应该用哪一个?推荐哪种方式?uint3即x、y、z的成员是否并排驻留在内存中?我不相信CUDA中的内置元组([u]int[2 | 4]、float[2 | 4]、double[2])有任何内在优势;它们的存在主要是

CUDA提供内置向量数据类型,如
uint2
uint4
等。使用这些数据类型有什么好处吗


假设我有一个元组,它由两个值a和B组成。将它们存储在内存中的一种方法是分配两个数组。第一个数组存储所有A值,第二个数组在与A值对应的索引处存储所有B值。另一种方法是分配一个类型为
uint2
的数组。我应该用哪一个?推荐哪种方式?
uint3
x
y
z
的成员是否并排驻留在内存中?

我不相信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是一个不方便的元素大小。

这有点推测性,但可能会增加@ArchaeaSoftware的答案

我主要熟悉计算能力2.0(费米)。对于这种架构,我不认为使用矢量化类型有任何性能优势,除了8位和16位类型

查看char4的声明:

struct __device_builtin__ __align__(4) char4
{
    signed char x, y, z, w;
};
该类型与4个字节对齐。我不知道
\u设备内置的功能是什么。也许它会在编译器中触发一些魔法

对于
float1
float2
float3
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到达一个执行内存事务的函数时,比如说从全局内存加载32位,芯片将在那时执行为warp中所有32个线程提供服务所需的事务。因此,如果所有访问的32位值都在单个128字节行内,则只需要一个事务。如果值来自不同的128字节行,则执行多个128字节事务。对于每个事务,当数据从内存中提取时,warp将保持大约600个周期(除非它位于L1或L2缓存中)


这样,我认为找出什么类型的方法获得最佳性能的关键是考虑哪种方法导致最少128字节的内存事务。


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


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

有一些好的信息与这里所说的主要结论相矛盾。

硬件有64位和128位加载和存储。一般来说,像
uint2
uint4
这样的结构,如果它们对您的数据和算法有意义的话,是有利的,因为它们可以增加每线程事务大小,从而更有效地使用可用带宽。您可以创建自己的自定义结构,但请确保它们像CUDA提供的结构那样指定对齐方式。@harrism因此,如果我没有错的话,这是这样的……uint2的所有成员将并排驻留在内存中,因此使用uint2类型的数组可以减少内存事务,因为其中一个会显示两个值。。是的。看看float4是如何在CUDA SDK的nbody、粒子和其他物理演示中使用的。+1我知道这是一篇老文章,但我认为你的第二和第三段非常重要。通常在并行计算中,我通常听到SOA是更好的,但这并不总是由NBoSE示例代码所证明的。“所以,我认为找出什么类型的方法获得最佳性能的关键是考虑哪种方法导致最少128字节的内存事务。”