ARM ARM实际上没有在这条指令上使用正确的方法,但是我发现它在其他地方用来知道它需要一个地址作为读取下一个值的位置的提示。
我的问题是,给定ldm/stm
指令的256字节紧密复制循环,比如说r4-r11 x 8,最好在复制之前,在每个指令对之间预取每个缓存行,或者不要这样做,因为所讨论的memcpy
不是同时读取和写入相同的内存区域。我非常确定我的缓存行大小是64字节,但它可能是32字节 - 在此处编写最终代码之前等待确认。
答案 0 :(得分:5)
来自Cortex-A Series Programmer's Guide,第17.4章(注意:ARM11的某些细节可能有所不同):
memcpy()的最佳性能是 使用整个缓存的LDM实现 然后编写这些值 使用整个缓存行的STM。 商店的对齐更多 比负荷对齐更重要。 应该使用PLD指令 在可能的情况。有四个PLD 加载/存储单元中的插槽。一个PLD 指令优先于 自动预取器,没有任何费用 就整数管道而言 性能。 PLD的确切时间 最佳memcpy()的说明可以 系统之间略有不同,但PLD 到前面三个缓存行的地址 目前的复制行是一个 有用的起点。
答案 1 :(得分:3)
在Linux内核中可以找到使用高速缓存行大小的LDM
/ STM
块和/或PLD
的合理通用复制循环的示例{{1} 3}}。这实现了伊戈尔上面提到的关于预加载的使用,并说明了阻塞。
请注意,在ARMv7上(高速缓存行大小通常为64字节),不能将LDM
完整的高速缓存行作为单个操作(自SP
/ {{PC
之后只能使用14个注册表无法触及1}})。因此,您可能必须使用两/四对LDM
/ STM
。
答案 2 :(得分:1)
要真正获得“最快”的ARM asm代码,您需要在系统上测试不同的方法。就ldm / stm循环而言,这个似乎对我来说效果最好:
// Use non-conflicting register r12 to avoid waiting for r6 in pld
pld [r6, #0]
add r12, r6, #32
1:
ldm r6!, {r0, r1, r2, r3, r4, r5, r8, r9}
pld [r12, #32]
stm r10!, {r0, r1, r2, r3, r4, r5, r8, r9}
subs r11, r11, #16
ldm r6!, {r0, r1, r2, r3, r4, r5, r8, r9}
pld [r12, #64]
stm r10!, {r0, r1, r2, r3, r4, r5, r8, r9}
add r12, r6, #32
bne 1b
上面的块假设您已经设置了r6,r10,r11,并且此循环在字段r11条件上倒数,而不是字节。我在Cortex-A9(iPad2)上测试了它,它似乎在该处理器上有相当不错的效果。但要小心,因为在Cortex-A8(iPhone4)上,至少对于较大的副本,NEON循环似乎比ldm / stm更快。