第9章 优化错误投机

当经常发生分支预测错误时,会导致显著地性能下降。因为CPU需要清理前面已经完成但是后面被证明是错误的投机工作,刷新整条流水线,并用正确的指令填充它。通常,现代CPU发生分支预测错误时会有15~20时钟周期的开销。

对于常规应用程序,有5%~10%的“错误投机”率是正常的当指标超过10%才值得关注

也许,唯一可以直接解决分支预测错误的方法就是消除分支本身。如何使用查表和断言代替分支。

9.1 用查表替换分支

int mapToBucket(unsigned v) {
    if (v >= 0 && v < 10) return 0;
    if (v >= 10 && v < 20) return 1;
    if (v >= 20 && v < 30) return 2;
    if (v >= 30 && v < 40) return 3;
    return -1;
}

int buckets[256] = {0..., 1..., 2...,...};

int mapToBucket(unsigned v) {
    if (v < sizeof(buckets) / sizeof(int))
        return buckets[v];
    return -1;
}

如果需要映射较大的值范围,分配一个非常大的数组并不实用。此时使用间隔映射数组数据结构来实现该目标,其使用的内存更少但有着对数级查询复杂度。

9.2 用断言替换分支

通过执行分支的两条路径然后选取正确的结果(断言)可以有效消除分支。

int a;
if (cond) {
    a = X();
} else {
    a = Y();
}

// opt
int a = cond ? X() : Y();

消除了分支预测错误的损失,但是有可能会比原始代码做更多的工作。收益取决于多做的工作和一次分支判断比较。

此外,断言的问题在于它限制CPU的并行执行能力,限制了CPU投机执行的能力。二分搜索是一个检验断言替换分支的权衡选择的经典例子:
        1. 对于超过CPU缓存大小的大数组搜索场景,基于分支版本性能更好。因为分支预测错误的性能损失相比于内存延迟要小;
        2. 对于能全部填充到CPU缓存的小数组,情况正好相反

再次强调,一定要测量确定替换分支是否是有收益的。

9.3 总结

        1. 仅在TMA报告显示错误投机指标高才尝试解决分支预测错误问题;
        2. 通过查表和断言替换分支是否有收益,一定要测试它是否真的更好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值