cuda记忆对齐

Pan*_*tis 16 cuda

在我的代码中,我使用结构以便于将争论传递给函数(我不使用结构数组,而是使用数组结构).当我在cuda-gdb中时,我会检查内核中的一个点,我将值赋给一个简单的结构

struct pt{
int i;
int j;
int k;
}
Run Code Online (Sandbox Code Playgroud)

即使我没有做一些复杂的事情,很明显成员应该有指定的价值,我得到...

当被问到堆栈的位置0时,堆栈上只有0个元素.

所以我在想,即使它不是一个数组,也许在这一点上存储器的对齐存在问题.所以我将头文件中的定义更改为

struct __align__(16) pt{
int i;
int j;
int k;
}
Run Code Online (Sandbox Code Playgroud)

但是,当编译器尝试编译使用相同定义的主机代码文件时,会出现以下错误:

错误:数字常量错误之前的预期unqualified-id:数字常量错误之前的预期')':';'之前的预期构造函数,析构函数或类型转换 代币

那么,我应该对主机和设备结构有两种不同的定义吗?

此外,我想问一下如何概括对齐的逻辑.我不是计算机科学家,因此编程指南中的两个例子并没有帮助我了解全局.

例如,如何对齐以下两个?或者,如何将6个浮子的结构对齐?还是4个整数?再次,我没有使用那些数组,但我仍然在内核或_ device _函数中使用这些结构定义了很多变量.

struct {
    int a;
    int b;
    int c;
    int d;
    float* el;    
} ;

 struct {
    int a;
    int b
    int c
    int d
    float* i;
    float* j;
    float* k;
} ;
Run Code Online (Sandbox Code Playgroud)

提前感谢您的任何建议或提示

har*_*ism 30

这篇文章中有很多问题.由于CUDA编程指南在解释CUDA中的对齐方面做得非常好,我将只解释一些在指南中不明显的内容.

首先,主机编译器给你错误的原因是主机编译器不知道什么__align(n)__意思,所以它给出了语法错误.您需要的是在项目的标题中添加以下内容.

#if defined(__CUDACC__) // NVCC
   #define MY_ALIGN(n) __align__(n)
#elif defined(__GNUC__) // GCC
  #define MY_ALIGN(n) __attribute__((aligned(n)))
#elif defined(_MSC_VER) // MSVC
  #define MY_ALIGN(n) __declspec(align(n))
#else
  #error "Please provide a definition for MY_ALIGN macro for your host compiler!"
#endif
Run Code Online (Sandbox Code Playgroud)

那么,我应该对主机和设备结构有两种不同的定义吗?

不,只是MY_ALIGN(n)像这样使用

struct MY_ALIGN(16) pt { int i, j, k; }
Run Code Online (Sandbox Code Playgroud)

例如,如何对齐以下两个?

首先,__align(n)__(或任何主机编译器风格)强制结构的内存开始于内存中多个n字节的地址.如果struct的大小不是double的倍数n,那么在这些结构的数组中,将插入填充以确保每个结构正确对齐.要为其选择适当的值n,您希望最小化所需的填充量.如编程指南中所述,硬件要求每个线程读取对齐到1,2,4,8或16字节的字.所以...

struct MY_ALIGN(16) {
  int a;
  int b;
  int c;
  int d;
  float* el;    
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,假设我们选择16字节对齐.在32位机器上,指针占用4个字节,因此struct占用20个字节.16字节对齐将浪费16 * (ceil(20/16) - 1) = 12每个结构的字节.在64位机器上,由于8字节指针,每个结构只会浪费8个字节.我们可以通过使用MY_ALIGN(8)来减少浪费.权衡将是硬件必须使用3个8字节加载而不是2个16字节加载来从内存加载结构.如果你没有受到负载的瓶颈,这可能是值得的权衡.请注意,您不希望为此结构对齐小于4个字节.

struct MY_ALIGN(16) {
  int a;
  int b
  int c
  int d
  float* i;
  float* j;
  float* k;
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,对于16字节对齐,您在32位计算机上每个结构只浪费4个字节,在64位计算机上浪费8个字节.它需要两个16字节的负载(或64位机器上的3个).如果我们对齐到8个字节,我们可以通过4字节对齐(64位机器上的8字节)完全消除浪费,但这会导致过多的负载.再次,权衡.

或者,如何将6个浮子的结构对齐?

再次,权衡:要么每个结构浪费8个字节,要么每个结构需要两个负载.

还是4个整数?

这里没有权衡.MY_ALIGN(16).

再次,我没有使用那些数组,但我仍然在内核或_ device _函数中使用这些结构定义了很多变量.

嗯,如果你没有使用这些数组,那么你可能根本不需要对齐.但是你如何分配给他们?正如您可能已经看到的那样,所有这些浪费都是值得担心的重要因素 - 这是在结构数组上支持数组结构的另一个好理由.

  • 多年以后,仍然是一个很好的答案!值得一提的是,英特尔的编译器也使用`__declspec(align(n))`.编译器定义了`__INTEL_COMPILER`,因此你可以将它添加到你的`MSVC`中.Clang定义了`__clang__`,并使用GCC的版本(`__attribute __((aligned(n)))`),所以你可以在那里添加它.这几乎涵盖了我必须处理的所有主要的(非专业的,即我不了解的ARM)编译器;)我遇到了麻烦,因为他们定义了一堆你不会想到的东西.我不记得具体细节,但解决办法是首先检查它. (2认同)

ein*_*ica 5

现在,您应该使用C++ 11 alignas说明符,它受到g++(包括与当前CUDA兼容的版本)和IIANM的支持nvcc.这应该可以节省您使用宏的必要性.