检测目标CPU上的对齐内存要求

我目前正在尝试构建一个代码,该代码可用于各种机器,从手持式口袋和传感器到数据中心的大型服务器。

这些体系结构之间的(许多)差异之一是对齐内存访问的要求。

“标准”x86 CPU不需要对齐的内存访问,但是如果不遵守规则,许多其他CPU需要它并产生exception。

到目前为止,我一直在使用packed属性(或pragma)强制编译器对已知存在风险的特定数据访问保持谨慎。 它工作正常。

问题是,编译器非常谨慎,以至于在此过程中会丢失大量性能。

由于性能很重要,我们最好重写代码的某些部分以专门处理严格对齐的cpus。 另一方面,这样的代码在cpus上会更慢,它支持未对齐的内存访问(例如x86),因此我们只想在需要严格对齐内存访问的cpus上使用它。

现在的问题是:如何在编译时检测目标架构是否需要严格对齐的内存访问? (或反过来)

我所知道的没有C实现提供了任何预处理器宏来帮助您解决这个问题。 由于您的代码应该在各种机器上运行,我假设您可以访问各种各样的机器进行测试,因此您可以通过测试程序找出答案。 然后你可以编写自己的宏,如下所示:

#if defined(__sparc__) /* Unaligned access will crash your app on a SPARC */ #define ALIGN_ACCESS 1 #elif defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) /* Unaligned access is too slow on a PowerPC (maybe?) */ #define ALIGN_ACCESS 1 #elif defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64) /* x86 / x64 are fairly forgiving */ #define ALIGN_ACCESS 0 #else #warning "Unsupported architecture" #define ALIGN_ACCESS 1 #endif 

请注意,未对齐访问的速度取决于它所跨越的边界。 例如,如果访问跨越4k页边界,则它将慢得多,并且可能存在导致其更慢的其他边界。 即使在x86上,一些未对齐的访问也不由处理器处理,而是由OS内核处理。 那非常慢。

也不能保证未来(或当前)实现不会突然改变未对齐访问的性能特征。 这种情况在过去发生过,可能在将来发生; PowerPC 601对于未对齐访问非常宽容,但PowerPC 603e却没有。

使事情进一步复杂化的事实是,您编写的用于进行未对齐访问的代码在跨平台的实现方面会有所不同。 例如,在PowerPC上,如果x是32位,则x x << 32x >> 32总是为0,但在x86上你没有这样的运气。

无论如何,为严格的内存对齐编写代码是个好主意。 即使在允许未对齐访问的x86系统上,您的未对齐读/写也会导致两次内存访问,并且某些性能将会丢失。 编写适用于所有CPU架构的高效代码并不困难。 要记住的简单规则是指针必须与您正在读取或写入的对象的大小对齐。 例如,如果写一个DWORD,那么(dest_pointer&3 == 0)。 使用诸如“UNALIGNED_PTR”类型之类的拐杖将导致编译器生成低效代码。 如果你有大量的遗留代码必须立即工作,那么使用编译器来“修复”这种情况是有意义的,但是如果它是你的代码,那么从一开始就把它写在所有系统上。