【问题标题】:ARM64 SIMD function bottlenecked by simple subtract command?ARM64 SIMD 功能受到简单减法命令的瓶颈?
【发布时间】:2019-03-17 22:57:15
【问题描述】:

我有一个函数,其签名为void aggregate(const char *string, int64_t length, void *dest),其目标是将string 中的每个字符映射到dest 中的相应位,如果该字符为'\"',则该位为1,否则为0。所以如果字符串是"\"aaaaaa\"...,那么0b10000001...会被写入dest。此函数一次处理来自string 的 32 个字节,因此length 需要是它的倍数。

无论如何,我有一个工作函数,但根据我的分析,它花费了超过 80% 的时间在 subs 指令上。我知道你必须小心处理普通寄存器和 SIMD 寄存器,但我不明白为什么这是一个瓶颈。我还尝试使用当前字符串指针和字符串结尾执行cmp,并且仅在当前指针小于结尾时循环。然而,这并没有帮助。我还尝试展开,以便运行一半或四分之一的 subs 指令,但这也无济于事。有什么想法吗?

#define vadds_raw v0
#define vadds vadds_raw##.16b
#define vrepquote v1.16b
#define vchrs0_raw v2
#define vchrs0 vchrs0_raw##.16b
#define stepmask_raw v7
#define stepmask stepmask_raw##.16b
#define halfmask_raw v8
#define adder_scratch v9

#define string x0
#define length x1
#define out x2
#define scratch_reg x3

.section    __TEXT,__text,regular,pure_instructions
.build_version ios, 12, 0
.globl    _aggregate
.p2align    2

_aggregate:
// load masks
movi vrepquote, #0x22

mov scratch_reg, 0x4080
movk scratch_reg, 0x1020, lsl 16
movk scratch_reg, 0x0408, lsl 32
movk scratch_reg, 0x0201, lsl 48
dup stepmask_raw.2d, scratch_reg

mov scratch_reg, 0xffff
movk scratch_reg, 0xffff, lsl 16
movk scratch_reg, 0xffff, lsl 32
movk scratch_reg, 0xffff, lsl 48

ins halfmask_raw.d[0], x31 // zero it out
ins halfmask_raw.d[1], scratch_reg

iter:
subs length, length, #16
ldur q2, [string]

cmeq vchrs0, vchrs0, vrepquote
and vchrs0, vchrs0, stepmask

movi.16b vadds_raw, #0
addv b0, vchrs0_raw.8b
and vchrs0, vchrs0, halfmask_raw.16b
addv b9, vchrs0
ins vadds_raw.b[1], adder_scratch.b[0]

str h0, [out]
add out, out, #2
add string, string, #16
b.hi iter
ret

【问题讨论】:

  • subs 真的有错还是分析器错误地归咎于它?
  • 我打赌这是一个分支错误预测
  • 你如何衡量这个?哪个分析器,哪个处理器?

标签: assembly optimization simd arm64


【解决方案1】:

分析器提供二进制中的地址作为位置。在这种情况下,它是 iter 标签。但是标签当然不占用二进制本身的空间,所以地址是subs指令的地址,它是循环结束时分支的目的地。

这表明您的程序中的瓶颈确实是分支,可能是由于分支错误预测。这可能是个好消息,因为这意味着您的 SIMD 逻辑没有阻止您的处理。

一个有趣的实验是在不同长度的输入上尝试你的函数。个人资料是否有很大变化?

【讨论】:

  • 不,配置文件没有太大变化。如何减少错误预测?另外,我很惊讶它会误判。在我的基准测试中,我运行了大约 5,000 个字符的数组,所以它不会很快开始预测 b.hi 将是真的吗?
  • 也许不是误判。只是需要执行分支,需要获取指令等。如果展开没有帮助,那么错误预测可能不是问题。重要的是内存访问和 SIMD 指令不是瓶颈
  • 我明白了,接下来我要调查什么?
  • 我会说展开循环,但你已经尝试过了。尝试提高性能的另一件事是对齐循环。一些处理器更喜欢对齐分支目标。例如,Cortex-A57 软件优化指南 (infocenter.arm.com/help/topic/com.arm.doc.uan0015b/…) 建议使用四字对齐。根据您的目标处理器,尝试使用p2align 指令(如果您使用gas 作为汇编程序)
  • 我在上面的示例中使用.p2align 2,但根据您所说的,我也尝试了 4 和 8。我还添加了一对 nop 指令,以便跳转从 0x800x30,但这些都没有帮助。
猜你喜欢
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
  • 1970-01-01
  • 2016-06-12
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
相关资源
最近更新 更多