SIMD本质:对齐操作不同于未对齐操作
SIMD intrinsics: aligned operation different than unaligned?
我开始学习SIMD的一些特性。我注意到,对于一些函数,有一个对齐和一个未对齐的版本,例如_mm_store_si128
和_mm_storeu_si128
。我的问题是,这些函数的执行是否不同,如果不是,为什么是两个不同的版本?
我会说"always align (whatever possible)",这样无论发生什么,你都会被覆盖。一些平台不支持非对齐访问,其他平台的性能会有很大的下降。如果您选择对齐访问,在任何情况下都将获得最佳性能。在某些平台上可能会有少量的内存成本,但这是值得的,因为如果采用SIMD,就意味着要提高性能。我想不出为什么要实现不对齐的代码路径。也许如果你必须处理一些旧的设计,这些设计并没有考虑到SIDM,但我想说这种可能性几乎为零。
我想说这同样适用于标量,正确的对齐在任何情况下都是正确的,并且在获得最佳性能时为您节省一些麻烦…
至于为什么不对齐访问可能会更慢,甚至不支持-这是由于硬件的工作方式。假设您有一个64位整数和一个64位内存控制器,如果您的整数正确对齐,内存控制器可以一次访问它。但是如果它被偏移,内存控制器将不得不做2个操作,加上CPU可能需要移动数据来正确地组合它。由于这是次优的,一些平台甚至不隐式地支持它,作为提高效率的手段。
在较旧的cpu上,对齐和未对齐的加载/存储之间存在很大的性能差异。在较新的cpu上,这种差异要小得多,但作为"经验法则",您仍然应该尽可能选择对齐的版本。
如果数据实际上是对齐的,那么不对齐的load/store将与对齐的store具有相同的性能。
-
unaligned ops:未对齐的数据会导致小的性能影响,但你的程序仍然可以工作。
-
aligned ops:未对齐的数据将导致错误,让您检测意外未对齐的数据,而不是无声地导致性能下降。
现代cpu对未对齐的加载有很好的支持,但是当加载越过缓存线边界时,仍然会有很大的性能损失。
当使用SSE时,对齐的负载可以作为内存操作数折叠到其他操作中。这稍微改善了代码大小和吞吐量。
当使用AVX时,这两种负载都可以折叠到其他操作中。(AVX的默认行为是允许不对齐的内存操作数)。如果对齐的负载没有折叠,并且产生movdqa
或movaps
,那么它们仍然会在未对齐的地址上发生故障。这甚至适用于128位操作的vex编码,您可以使用正确的编译选项,而无需使用128b intrinsic更改源代码。
对于开始使用intrinsic,我建议总是使用未对齐的load/store intrinsic。(但至少在一般情况下,请尽量使您的数据对齐)。如果您担心未对齐的数据会导致问题,请在性能调优时使用aligned
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 如何创建一个QTableWidgetItem,用长文本右对齐,左边有省略号
- 我可以检测和更改 gcc/g++ 中结构的当前数据对齐设置吗?
- 64位机器上的C++内存对齐
- 为什么我可以将变量存储在不是其最小对齐方式的倍数的地址?
- 使 std::vector 分配对齐内存的现代方法
- C++ cout 将双精度对齐到精度 2 并正确对齐
- 在 64 位边界上对齐C++结构数组?
- 使用 g++7 构建的代码在访问未对齐的内存时崩溃
- 在 capnp FlatArrayMessageReader 的对齐内存缓冲区中接收 zmq 消息
- 是否值得对齐变量?
- 初始化派生结构的基部分/意外打包派生结构字段以对齐基结构的间隙
- 对齐和对齐的实际用例C++关键字
- 在英特尔上自然对齐的POD类型的保证原子操作
- C++轴对齐的矩形操作向量和字符串
- 存储SSE操作结果时的对齐要求
- 展开操作期间遇到无效或未对齐的堆栈
- 在c++中声明、操作和访问未对齐内存
- SIMD本质:对齐操作不同于未对齐操作
- 对齐指针操作