aarch64上未对齐的SIMD加载/存储的性能

问题描述 投票:3回答:3

older answer表示aarch64支持未对齐的读/写,并提及性能成本,但不清楚答案是否仅涵盖ALU或SIMD(128位寄存器)操作。

相对于对齐的128位NEON加载和存储,在aarch64上,未对齐的128位NEON加载和存储的速度有多慢(如果有的话)?

对于未对齐的SIMD加载和存储(如SSE2的情况)是否有单独的指令,或者已知对齐的加载/存储与可能未对齐的加载/存储相同的指令?

alignment simd neon arm64
3个回答
3
投票

根据Cortex-A57 Software Optimization Guide第4.6节“加载/存储对齐”,它说:

ARMv8-A架构允许任意对齐多种类型的加载和存储访问。 Cortex-A57处理器可处理大多数未对齐的访问,而不会造成性能损失。但是,有些情况会降低带宽或产生额外的延迟,如下所述:

  • 加载跨越缓存行(64字节)边界的操作
  • 存储跨越16字节边界的操作

因此,它可能取决于您使用的处理器,故障(A57,A72,A-72,A-75)或按顺序(A-35,A-53,A-55)。我没有找到有序处理器的任何优化指南,但是它们有一个硬件性能计数器,您可以使用它来检查未对齐指令的数量是否会影响性能:

    0xOF_UNALIGNED_LDST_RETIRED Unaligned load-store

这可以与perf工具一起使用。

AArch64中没有针对未对齐访问的特殊说明。


2
投票

如果必须拆分加载/存储或跨越高速缓存行,则至少需要一个额外的周期。

有详尽的表格,用于指定Cortex-A8(有序)和Cortex-A9(部分OoO)的各种对齐和寄存器数量所需的周期数。例如,具有一个reg的vld1对于未对齐访问与64位对齐访问具有1个周期的惩罚。

Cortex-A55(按顺序)最多可以进行64位加载和128位存储,因此,its optimization manual的3.3节规定了1个周期的惩罚:

•加载跨越64位边界的操作 •跨越128位边界的128位存储操作

Cortex-A75(OoO)对its optimization guide的5.4节进行处罚:

•加载跨越64位边界的操作。 •在AArch64中,所有跨越128位边界的商店。 •在AArch32中,所有跨越64位边界的存储。

就像在吉列尔莫的回答中一样,A57(OoO)的惩罚是:

•加载跨越缓存行(64字节)边界的操作 •存储跨越[128位]边界的操作

我有点怀疑,鉴于A55和A75的确,A57不会因为跨越64位边界而受到惩罚。所有这些都有64字节的缓存行;他们都应该对穿越缓存线也有惩罚。最后,请注意有unpredictable behavior for split access crossing pages

从使用Cavium ThunderX的一些粗略测试(没有穿孔计数器)开始,似乎更接近于2周期惩罚,但这可能是在循环中背对背未对齐载荷和存储的附加效应。


AArch64 NEON指令不区分对齐和未对齐(例如,参见LD1)。对于AArch32 NEON,在寻址(VLDn)中静态指定对齐:

vld1.32 {d16-d17}, [r0]    ; no alignment
vld1.32 {d16-d17}, [r0@64] ; 64-bit aligned
vld1.32 {d16-d17}, [r0:64] ; 64 bit-aligned, used by GAS to avoid comment ambiguity

我不知道没有对齐限定符的对齐访问是否比在AArch32模式下运行的最近芯片上使用对齐限定符访问更慢。 ARM的一些旧文档鼓励尽可能使用限定符。 (相比之下,英特尔改进了他们的芯片,使得未对齐和对齐的移动在地址对齐时执行相同的操作。)

如果您使用内在函数,MSVC具有接受对齐的_ex后缀变体。让gCC发出对齐限定符的可靠方法是使用__builtin_assume_aligned

// MSVC
vld1q_u16_ex(addr, 64);
// GCC:
addr = (uint16_t*)__builtin_assume_aligned(addr, 8);
vld1q_u16(addr);

0
投票

aarch64上不使用对齐提示。它们是透明的。如果指针与数据类型大小对齐,则性能优势是自动的。

如果有疑问,GCC / Clang在变量声明中使用__attribute__((__aligned__(16)))

© www.soinside.com 2019 - 2024. All rights reserved.