首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从精心设计的子例程返回到修改后的返回地址时BR/RET的时间差

从精心设计的子例程返回到修改后的返回地址时BR/RET的时间差
EN

Stack Overflow用户
提问于 2022-01-01 02:34:19
回答 1查看 127关注 0票数 2

在我尝试64位ARM架构的冒险中,我发现了一个奇怪的速度差异,这取决于br还是ret是否用于从子程序返回。

代码语言:javascript
复制
; Contrived for learning/experimenting purposes only, without any practical use
foo:
    cmp     w0, #0
    b.eq    .L0
    sub     w0, w0, #1
    sub     x30, x30, #4
    ret
.L0:
    ret ; Intentionally duplicated 'ret'

该子例程的目的是让foo的调用方“重新输入”foo w0时间,首先让foo返回到调用foo的指令(即在x30指向的指令之前)。有了一些粗略的时间,由于w0值足够高,平均花费了大约1362毫秒。奇怪的是,将第一个ret替换为br x30使其运行速度提高了一倍,平均只需550毫秒左右。

如果将测试简化为只重复调用带有裸ret/br x30的子例程,那么时间差异就会消失。是什么使上面设计的子例程在使用ret时变慢?

我在某种ARMv8.2 (Cortex-A76 + Cortex-A55)处理器上测试了这一点。我不知道big.LITTLE会在多大程度上搅乱时间,但在多次运行中,它们看起来相当一致。这绝不是一个真正的微基准,而是一个“如果运行N次大约需要多长时间”的问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-01 02:41:51

大多数现代的微体系结构都有一个特殊的呼叫/返回预测器,在实际程序中往往是相互匹配的。(对于许多调用站点的函数来说,任何其他方法都很难预测返回:它是一个间接分支。)

通过手动处理返回地址,您将使那些返回预测错误。因此,每个ret都会导致一个分支的错误预测,除了没有使用x30的那个分支。

但是,如果您使用的是一个间接分支,而不是一个专门被认为是ret成语的分支,例如br x30,则CPU使用其标准的间接分支预测方法,当br重复到相同的位置时,这种方法做得很好。

google快速搜索从ARM中为Cortex-R4找到一些关于32位模式(4入口循环缓冲区)微体系结构上的返回预测器堆栈的信息:https://developer.arm.com/documentation/ddi0363/e/prefetch-unit/return-stack

对于x86来说,https://blog.stuffedcow.net/2018/04/ras-microbenchmarks/是一篇很好的关于一般概念的文章,也是关于各种x86微体系结构如何在必须回滚的callret指令的误判执行中保持其预测准确性的一些细节。

(x86有一个实际的ret操作码;ARM64是相同的:ret操作码类似于br,但暗示这是一个函数返回。其他一些RISCs,如RISC-V,没有单独的操作码,只需假设具有链接寄存器的分支到寄存器就是一个返回。)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70546711

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档