【IT168 文档】CUDA的nvcc编译器支持数据结构struct的对齐,以此来提高速度。但当我们想从C++里创建数据结构,然后传到GPU里,用GPU处理的时候,我们就必须注意这个对齐了,怎么在C++里模拟CUDA的对齐呢?今天我发现,其实,结构的内存对齐并不是nvcc的魔法,nvcc其实也只是使用了C++的对齐机制。但为什么要多出一个__align__关键字呢?原来,C++的结构对齐并不是一个跨平台的标准,所以nvcc用__align__来统一。
为了找到模拟的方法,我分别在Windows和Linux下搜索nvcc的中间输出文件(xxx.cpp1.ii文件,其中xxx是你的cu文件的文件名),找到了使用的C++关键字,于是我定义如下宏,来在C++中模拟CUDA的对齐机制:
#if defined (__CUDACC__)
#define ALIGN16 __align__(16)
#elif defined (__GCCXML__)
#define ALIGN16
#elif defined (_MSC_VER)
#define ALIGN16 __declspec(align(16))
#elif defined (__GNUC__)
#define ALIGN16 __attribute__((__aligned__(16)))
#else
#error compiler unsupport for alignment
#endif
#define ALIGN16 __align__(16)
#elif defined (__GCCXML__)
#define ALIGN16
#elif defined (_MSC_VER)
#define ALIGN16 __declspec(align(16))
#elif defined (__GNUC__)
#define ALIGN16 __attribute__((__aligned__(16)))
#else
#error compiler unsupport for alignment
#endif
在测试的时候,我还发现一个有趣的现象,Windows和Linux对0大小的结构,其sizeof结果不尽相同。
假设我们有个模板:
template <unsigned int len, typename value_type>
struct ALIGN16 foo
{
value_type x[len];
};
struct ALIGN16 foo
{
value_type x[len];
};
然后我们用测试程序输出其sizeof结果:
首先是Windows下的输出:
sizeof(foo <0, float>) = 16
sizeof(foo <1, float>) = 16
sizeof(foo <2, float>) = 16
sizeof(foo <3, float>) = 16
sizeof(foo <4, float>) = 16
sizeof(foo <5, float>) = 32
sizeof(foo <6, float>) = 32
sizeof(foo <7, float>) = 32
sizeof(foo <8, float>) = 32
sizeof(foo <1, float>) = 16
sizeof(foo <2, float>) = 16
sizeof(foo <3, float>) = 16
sizeof(foo <4, float>) = 16
sizeof(foo <5, float>) = 32
sizeof(foo <6, float>) = 32
sizeof(foo <7, float>) = 32
sizeof(foo <8, float>) = 32
而Linux下的输出:
sizeof(foo <0, float>) = 0
sizeof(foo <1, float>) = 16
sizeof(foo <2, float>) = 16
sizeof(foo <3, float>) = 16
sizeof(foo <4, float>) = 16
sizeof(foo <5, float>) = 32
sizeof(foo <6, float>) = 32
sizeof(foo <7, float>) = 32
sizeof(foo <8, float>) = 32
sizeof(foo <1, float>) = 16
sizeof(foo <2, float>) = 16
sizeof(foo <3, float>) = 16
sizeof(foo <4, float>) = 16
sizeof(foo <5, float>) = 32
sizeof(foo <6, float>) = 32
sizeof(foo <7, float>) = 32
sizeof(foo <8, float>) = 32
不同之处在于foo<0, float>,因为对于struct foo { char a[0]; }, 其sizeof在Windows下是1,如果我们对齐到16,则是16;而在Linux下,其sizeof是0,对齐到16则是0。