SIMD本质:对齐操作不同于未对齐操作

SIMD intrinsics: aligned operation different than unaligned?

本文关键字:操作 对齐 不同于 本质 SIMD      更新时间:2023-10-16

我开始学习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的默认行为是允许不对齐的内存操作数)。如果对齐的负载没有折叠,并且产生movdqamovaps,那么它们仍然会在未对齐的地址上发生故障。这甚至适用于128位操作的vex编码,您可以使用正确的编译选项,而无需使用128b intrinsic更改源代码。

对于开始使用intrinsic,我建议总是使用未对齐的load/store intrinsic。(但至少在一般情况下,请尽量使您的数据对齐)。如果您担心未对齐的数据会导致问题,请在性能调优时使用aligned