无分支堆排序为何比有分支版本快1.5倍?
堆排序分支优化带来1.5倍提速的深层疑问
我了解CPU分支预测惩罚等概念,也知道无分支代码能提升性能,但想理解某Rust代码补丁为何让堆排序速度提升1.5倍(而非预期的1.1倍左右)。PR作者在Zen 3上测得1.5倍提速,我在Zen 2(Ryzen 3900x)上测得的提速略高。
代码修改对比
- if child + 1 < v.len() && is_less(&v[child], &v[child + 1]) { - child += 1; + if child + 1 < v.len() { + child += is_less(&v[child], &v[child + 1]) as usize; }
相关前置说明
- 查看汇编代码后确认:
if块内的child += 1被转换为简单的寄存器间移动操作,编译器用两个寄存器分别保存child和child+1,因此if块内无内存访问。 - 测试使用的数组包含10k元素,可完全放入CPU的L1缓存。
我对提速的现有理解
- AMD uProf分析结果:
- 无分支版本的CPI约为0.45,有分支版本约为0.9。
- 无分支版本的分支误预测率约0.5%,有分支版本约10%(针对所有分支,其他分支的预测难度极低)。
- 整个循环的汇编代码包含24条指令,若CPI=0.45,完美分支预测下约需11-12个周期。
- 结合多数分支预测近乎完美的情况,推测被优化的目标分支误预测率约25%-30%(或更高)。
- 根据微架构技术文档,Zen 3的分支误预测惩罚为18周期。若误预测率为30%,每个循环会额外增加约6周期,导致循环整体慢33%(计算方式:6/(12+6))。
疑问
我的上述理解是否正确?有没有遗漏的关键因素?还有哪些工具能帮助我深挖具体细节?
更新
- 已上传无分支版本与未优化版本的汇编代码。
- 已生成对应的汇编代码对比页面。
内容的提问来源于stack exchange,提问作者Hadi Moshayedi
相关产品推荐
相关产品推荐

