我正在使用向量和矩阵,有人建议我应该使用SSE而不是使用float数组。然而,在阅读C内在函数和汇编指令的定义时,看起来有一些函数的不同版本,其中向量必须是“16字节对齐”,而较慢的版本,其中向量未对齐。矢量是16字节对齐的意思是什么?如何确保我的向量是16字节对齐的?
答案 0 :(得分:7)
对齐可确保对象在地址上对齐,该地址是2的幂的倍数。 16字节对齐意味着地址的数值是16的倍数。对齐非常重要,因为CPU通常效率较低或者无法加载没有所需对齐的内存。
您的ABI确定类型的自然对齐方式。通常,整数类型和浮点类型与它们自己的大小或CPU可以一次处理的那种最大对象的大小对齐,以较小为准。例如,在64位Intel机器上,32位整数在4个字节上对齐,64位整数在8个字节上对齐,128位整数也在8个字节上对齐。 / p>
结构和联合的对齐与其最对齐的区域相同。这意味着如果您的struct
包含一个具有2字节对齐的字段和另一个具有8字节对齐的字段,则该结构将对齐为8个字节。
在C ++中,您可以像alignof
运算符一样使用sizeof
运算符来获取类型的对齐方式。在C中,当您包含<stdalign.h>
时,相同的结构可用;或者,您可以使用_Alignof
而不包含任何内容。
AFAIK,没有标准的方法强制对齐成为C或C ++中的特定值,但是有一些特定于编译器的扩展可以做到这一点。在Clang和GCC上,您可以使用__attribute__((aligned(N)))
属性:
struct s_Stuff {
int var1;
short var2;
char padding[10];
} __attribute__((aligned(16)));
(Example.)
(此属性不与__attribute__((align(N)))
混淆,__declspec(align(N))
设置变量的对齐方式。)
在我的脑海中,我不确定Visual Studio,according to SoronelHaetir,那将是__m128
。不知道它在结构声明中的位置。
在向量指令的上下文中,对齐非常重要,因为人们倾向于创建浮点值数组并对其进行操作,而不是使用已知对齐的类型。但是,__m256
,__m512
和_m128i
(及其所有变体,如<emmintrin.h>
等)来自malloc
,如果您的编译器环境具有它,则是aligned_alloc
保证在对齐的内在函数上使用适当的边界。
根据您的平台,aligned_alloc
可能会也可能不会返回在矢量对象的正确边界上对齐的内存。在C11中引入了malloc
来解决这些问题,但并非所有平台都支持它。
aligned_alloc
; malloc
返回平台支持的最紧急对齐的对象; malloc
; aligned_alloc
返回在最大对齐上对齐的对象,VC ++自然会将对象放在没有对齐规范的情况下;将_aligned_malloc
用于矢量类型free
返回对象aligned on an 8- or 16-byte boundary;使用void* aligned_malloc(size_t size, size_t alignment) {
intptr_t alignment_mask = alignment - 1;
void* memory = malloc(size + alignment_mask);
intptr_t unaligned_ptr = (intptr_t)memory;
intptr_t aligned_ptr = (unaligned_ptr + alignment_mask) & ~alignment_mask;
return (void*)aligned_ptr;
}
。一般情况下,可以请求稍微更多的内存,并以最小的惩罚执行对齐(除了你自己编写一个2,3,4,5,6,7,8,9,11,12,...
- 类似的函数,它将接受一个这个函数返回的指针):
10
纯粹主义者可能会认为将指针视为整数是邪恶的,但在撰写本文时,他们可能无法获得实用的跨平台解决方案来提供交换。
答案 1 :(得分:2)
xx-byte alignment意味着变量的存储器地址模xx为0。
确保这是一个特定于编译器的操作,例如visual c ++有__declspec(align(...)),这将适用于编译器分配的变量(例如在文件或函数范围),对齐有点困难对于动态内存,你可以使用aligned_malloc,虽然你的库可能已经保证了malloc的16字节对齐,但通常需要这样调用的是更大的对齐。
答案 2 :(得分:-9)
新修改以改进并集中我对特定查询的回答
为了确保内存中的数据对齐,C中有特定的功能强制执行此操作(假设您的数据兼容 - 您的数据匹配或离散地适合您所需的对齐)
要使用的功能是[_aligned_malloc][1]
而不是香草malloc
。
// Using _aligned_malloc
// Note alignment should be 2^N where N is any positive int.
int alignment = 16;
ptr = _aligned_malloc('required_size', alignment);
if (ptr == NULL)
{
printf_s( "Error allocation aligned memory.");
return -1;
}
这将(如果成功)强制您的数据在16字节边界上对齐,并且应满足SSE的要求。
旧答案,我对结构成员对齐感到困惑,这很重要 - 但不是直接回答查询
要确保结构成员字节对齐,您可以小心如何在结构中排列成员(最大的第一个),或者可以在编译器设置,成员属性或结构属性中设置此(在某种程度上)。
假设32位机器,4字节整数:这仍然是4字节在内存中对齐(第一个最大成员是4个字节),但填充为16字节大小。
struct s_Stuff {
int var1; /* 4 bytes */
short var2; /* 2 bytes */
char padding[10]; /* ensure totals struct size is 16 */
}
编译器通常会填充每个成员以协助自然对齐,但填充也可能位于结构的末尾。这是 struct member data alignment 。
较旧的编译器结构成员对齐设置可能类似于下面的这两个图像...但这与数据对齐不同,后者与内存分配和数据存储有关。
当Borland使用短语(来自图像)数据对齐时,它会让我感到困惑,而MS则使用Struct成员对齐。 (虽然它们都是指具体的结构成员对齐)
为了最大限度地提高效率,您需要为硬件编写代码(或者在这种情况下使用矢量处理),因此我们假设32位,4字节整数等。然后您希望使用紧结构来节省空间,但填充结构可能提高速度。
struct s_Stuff {
float f1; /* 4 bytes */
float f2; /* 4 bytes */
float f3; /* 4 bytes */
short var2; /* 2 bytes */
}
这个struct 可能被填充以使结构成员对齐到4字节倍数....编译器将执行此操作,除非您指定它保持单字节 struct member alignment - 所以大小ON FILE可能是14个字节,但仍然在MEMORY中这个结构的数组大小为16个字节(浪费2个字节),未知数据对齐(默认情况下可能是8个字节{{1但是不能保证。如上所述,您可以在某些平台上强制使用malloc
在内存中进行数据对齐。
同样关于结构中的_aligned_malloc
,编译器将使用最大成员的倍数来设置对齐。或者更具体地说:
结构始终与最大类型的对齐方式对齐 要求
...来自here
如果您正在使用UNION,那么您被迫使用最大可能的结构是正确的,请参阅here
检查您的编译器设置是否与您想要的struct member alignment / padding不相矛盾,否则您的结构可能会与您期望的结构大小不同。
现在,为什么它更快?参见here,它解释了对齐如何允许硬件传输离散的数据块,并最大限度地利用传递数据的硬件。也就是说,不需要在每个阶段分割或重新安排数据 - 通过硬件处理
作为一项规则,最好将您的编译器设置为与您的硬件(和平台操作系统)产生共鸣,以便您的对齐(和填充)最适合您的硬件处理能力。 32位机器通常在4字节(32位)成员对齐时效果最佳,但是使用4字节成员对齐写入文件的数据可能会占用比预期更多的空间。
特别是关于SSE向量,作为这个link状态,4 * 4字节是确保16字节对齐的最佳方式,也许就像这样。 (他们在这里引用数据对齐)
member alignment
或只是一个struct s_data {
float array[4];
}
或floats
。