cuda内存对齐

cuda内存对齐,cuda,Cuda,在我的代码中,我使用结构是为了方便将参数传递给函数(我不使用结构数组,而是通常使用数组的结构)。 当我在cuda gdb中时,我检查内核中的一个点,在这里我给一个简单的结构赋值,比如 struct pt{ int i; int j; int k; } 尽管我没有做一些复杂的事情,而且很明显,成员们应该有指定的价值观,但我得到 询问堆栈的位置0,堆栈上只有0个元素 所以我在想,即使它不是一个数组,也可能在这一点上内存的对齐有问题。因此,我将头文件中的定义更改为 struct __align__(

在我的代码中,我使用结构是为了方便将参数传递给函数(我不使用结构数组,而是通常使用数组的结构)。 当我在cuda gdb中时,我检查内核中的一个点,在这里我给一个简单的结构赋值,比如

struct pt{
int i;
int j;
int k;
}
尽管我没有做一些复杂的事情,而且很明显,成员们应该有指定的价值观,但我得到

询问堆栈的位置0,堆栈上只有0个元素

所以我在想,即使它不是一个数组,也可能在这一点上内存的对齐有问题。因此,我将头文件中的定义更改为

struct __align__(16) pt{
int i;
int j;
int k;
}
但是,当编译器尝试编译使用相同定义的主机代码文件时,会出现以下错误:

错误:应为数字常量之前的非限定id错误:应为 数值常量错误前的“)”:应为构造函数、析构函数、, 或在“;”之前进行类型转换代币

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

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

例如,以下两个应该如何对齐?或者,一个有6个浮点数的结构应该如何对齐?还是4个整数?同样,我没有使用这些数组,但我仍然在内核或uu设备u函数中使用这些结构定义了很多变量

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;
} ;

提前感谢您的建议或提示

这篇文章中有很多问题。由于《CUDA编程指南》在解释CUDA中的对齐方面做得相当好,因此我将只解释一些在指南中不明显的事情

首先,主机编译器给您错误的原因是因为主机编译器不知道
\uuuu align(n)\uuuu
的意思,所以它给出了语法错误。您需要的是在项目的标题中添加如下内容

#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
那么,我应该对主机和设备结构有两种不同的定义吗

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

struct MY_ALIGN(16) pt { int i, j, k; }
例如,以下两个应该如何对齐

首先,
\uuuu align(n)\uuuu
(或任何一种主机编译器风格),强制结构的内存从内存中的地址开始,该地址是
n
字节的倍数。如果结构的大小不是
n
的倍数,那么在这些结构的数组中,将插入填充以确保每个结构正确对齐。要为
n
选择合适的值,您需要最小化所需的填充量。如编程指南中所述,硬件要求每个线程读取与1、2、4、8或16字节对齐的字。所以

struct MY_ALIGN(16) {
  int a;
  int b;
  int c;
  int d;
  float* el;    
};
在本例中,假设我们选择16字节对齐。在32位机器上,指针需要4个字节,因此结构需要20个字节。16字节对齐将浪费
16*(ceil(20/16)-1)=每个结构12个
字节。在64位计算机上,由于使用8字节指针,每个结构只会浪费8字节。我们可以使用
MY\u 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;
};
在这种情况下,对于16字节对齐,在32位机器上每个结构只浪费4字节,在64位机器上每个结构只浪费8字节。它需要两个16字节的加载(或64位机器上的3个)。如果我们对齐到8字节,我们可以通过4字节对齐(64位机器上为8字节)完全消除浪费,但这会导致负载过大。同样,权衡

或者,一个有6个浮点数的结构应该如何对齐

同样,权衡:要么每个结构浪费8字节,要么每个结构需要两次加载

还是4个整数

这里没有折衷<代码>我的对齐(16)

同样,我没有使用这些数组,但我仍然在内核或uu设备u函数中使用这些结构定义了很多变量

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;
} ;

嗯,如果您不使用这些数组,那么您可能根本不需要对齐。但是你是如何分配给他们的呢?正如您可能看到的,所有这些浪费都是值得担心的,这是支持数组结构而不是结构数组的另一个很好的理由

现在,您应该使用C++11,这是由
g++
支持的(包括与当前CUDA兼容的版本),以及由
nvcc
支持的IIANM。这应该可以省去你使用宏的麻烦。

我想你正在寻找这个[,由@harrism自己回答。[1]:非常感谢您的回答。我最多只希望有一个指向外部参考的链接,这更是一个关于对齐的完整课程。我很荣幸。我的代码确实使用数组结构。我使用类似pt的结构(如上所述)在更小的范围内,为了便于将参数从内核内传递到被调用的u设备uu函数,当我试图从cuda-gdb查询它们的值时,它们就像是不可见的。很乐意提供帮助。向上投票不会出错。:)不确定这是否有助于cuda gdb问题。根据我的经验,设备代码调试器没有sn并不总是显示所有的值——仅显示范围/活动a中立即处于当前暂停代码位置的值。因此,为了清楚起见:当我收到“请求堆栈位置0时,堆栈上只有0个元素。”gdb…这意味着gdb不允许我查询该值(?),或者变量还没有定义,和/或没有为它指定值?我更关心的是程序执行本身会发生什么,而不是通过gdb看到什么。当然,我不熟悉这一点