CUDA提供了内置的矢量数据类型 uint2
, uint4
等等。使用这些数据类型有什么好处吗?
让我们假设我有一个由两个值A和B组成的元组。将它们存储在内存中的一种方法是分配两个数组。第一个数组存储所有A值,第二个数组存储与A值对应的索引处的所有B值。另一种方法是分配一个类型的数组 uint2
。我应该使用哪一个?推荐哪种方式?会员吗? uint3
即 x
, y
, z
在记忆中并排居住?
CUDA提供了内置的矢量数据类型 uint2
, uint4
等等。使用这些数据类型有什么好处吗?
让我们假设我有一个由两个值A和B组成的元组。将它们存储在内存中的一种方法是分配两个数组。第一个数组存储所有A值,第二个数组存储与A值对应的索引处的所有B值。另一种方法是分配一个类型的数组 uint2
。我应该使用哪一个?推荐哪种方式?会员吗? uint3
即 x
, y
, z
在记忆中并排居住?
这将有点推测,但可能会增加@ 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
, 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
此时的值,其他值(y
, z
, w
由于128字节的事务,将被拉入L1。当warp稍后尝试访问它们时,它们可能不再在L1中,因此必须发出新的全局内存事务。此外,如果编译器能够发出更宽的指令以同时读取更多的值,以备将来使用,它将使用寄存器来存储负载点和使用点之间的值,这可能会增加寄存器的使用内核。
另一方面,如果将值打包到数组结构中,则可以使用尽可能少的事务来为负载提供服务。所以,从阅读时 x
数组,只 x
值在128字节的事务中加载。这可能会导致更少的事务,更少依赖缓存以及计算和内存操作之间更均匀的分配。
我不相信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是一个不方便的元素大小。
有一些很好的信息 在另一个线程中 这与这里所说的大部分主要结论相矛盾。