Branch Prediction – Lab4

Branch Prediction – Lab4

代码开源地址:https://github.com/coder-shx/qrio_handout

1)实验目的

通过扩展QRIO中的工具来练习有关分支预测的知识,基于程序中分支的采集/未采集结果,分析不同预测器的预测失误率。

2)实验设计

1. Static Predictor

 void branch(bool taken, unsigned long pc) override {
    /* TODO 1: static predictor                             */
    /* bool _predict:                                       */
    /*   true: predict the branch will always be taken      */
    /*   false: predict the branch will always be not-taken */
    // 总预测数加一
    _total++;
    // 如果预测错误,则未命中数加一
    if(taken!=_predict) {_miss++;}
  }

预测逻辑

  • 构造时由 _predict 决定:true 则始终预测“跳转(taken)”,false 则始终预测“不跳转(not-taken)”。

统计更新

  • 每遇到一次分支,_total++;如果实际结果 taken 与预测 _predict 不符,则 _miss++

2. FlipFlopPredictor

void branch(bool taken, unsigned long pc) override {
    /* TODO 2: flip-flop predictor */
    /* char _hbt[N]: history branch table                   */
    /* pc_bit: number of PC bits used to index the table    */
    // 更新总分支次数
    _total++;
    // 计算索引:pc/4 的低 _pc_bit 位
    unsigned int index = (pc >> 2) & ((1 << _pc_bit) - 1);
    // 读取历史分支表中的预测值
    bool prediction = _hbt[index];
    // 如果预测错误,更新未命中次数
    if (prediction != taken) {
      _miss++;
    }
    // 更新历史分支表中的值
    _hbt[index] = taken;
  }

索引计算

  • 由于 PC 恒为 4 字节对齐,先做 pc >> 2,再取其低 _pc_bit 位:

    index = (pc >> 2) & ((1 << _pc_bit) - 1);
    

预测与更新

  • 预测值即 _hbt[index](0 表示预测 NT,1 表示预测 T)。
  • 比较后更新命中统计,并将该表项直接设置为本次 taken

3. CorrelatePredictor

void branch(bool taken, unsigned long pc) override {
    /* TODO 3: correlating predictor predictor                              */
    /* (m,n)*T correlating predictor means a table with T n-bit predictors, */
    /* m bits used to represent the taken/not-taken of the last m branches. */
    /* Here, n is 2 that we use 2-bit predictors.                           */
    /*                                                                      */
    /* char _hbt[N]: history branch table                                   */
    /* int _history: records taken/not-taken sequences of previous branches */
    /* int _pc_bit: number of PC bits used to index the table               */
    /* int _history_bit: number of history bits used to index the table     */
    _total++;
    // 计算表大小:2^(pc_bit + history_bit)
    unsigned int hist_mask = (1u << _history_bit) - 1;
    unsigned int pc_mask  = (1u << _pc_bit) - 1;
    unsigned int hist_bits = _history & hist_mask;
    unsigned int pc_bits   = (pc >> 2) & pc_mask;
    unsigned int idx = (hist_bits << _pc_bit) | pc_bits;
    // 读取 2-bit 饱和计数器状态(0,1:预测 NT;2,3:预测 T)
    unsigned char cnt = _hbt[idx];
    bool prediction = (cnt >= 2);
    if (prediction != taken) {
        _miss++;
    }
    // 更新 2-bit 计数器
    if (taken) {
        if (cnt < 3) _hbt[idx] = cnt + 1;
    } else {
        if (cnt > 0) _hbt[idx] = cnt - 1;
    }
    // 更新全局历史:低 history_bit 位左移并插入当前结果
    _history = (( (_history << 1) | (taken ? 1 : 0) ) & hist_mask);
  }

联合索引

  • 全局历史的低 _history_bit 位和 (pc>>2) 的低 _pc_bit 位拼接:

    idx = (history_bits << pc_bit) | pc_bits
    

2-bit 饱和计数器

  • 状态值 0,1 → 预测 not-taken;2,3 → 预测 taken;
  • 更新时注意边界 [0,3] 饱和值。

历史寄存器滚动

  • 每次插入最新分支结果,左移一位并截断:

    history = ((history << 1) | (taken ? 1 : 0)) & hist_mask;
    

4. GSharePredictor

void branch(bool taken, unsigned long pc) override {
    /* TODO 4: GSharePredictor          */
    /* index = pc-bit XOR history-bit   */
    _total++;
    unsigned int mask = (1u << _pc_bit) - 1;
    // 取 pc/4 的低 pc_bit 位
    unsigned int pc_bits = (pc >> 2) & mask;
    // 取历史的低 pc_bit 位
    unsigned int hist_bits = _history & mask;
    // XOR 得到最终索引
    unsigned int idx = pc_bits ^ hist_bits;
    // 读取、预测、更新与 Correlate 相同
    unsigned char cnt = _hbt[idx];
    bool prediction = (cnt >= 2);
    if (prediction != taken) {
        _miss++;
    }
    if (taken) {
        if (cnt < 3) _hbt[idx] = cnt + 1;
    } else {
        if (cnt > 0) _hbt[idx] = cnt - 1;
    }
    // 更新历史:同上,记录最新一次分支结果
    _history = (((_history << 1) | (taken ? 1 : 0)) & mask);
  }

XOR 索引

  • 将 PC 低位与全局历史低位做异或,得到分支表索引:

    idx = ((pc>>2)&mask) ^ (history & mask)
    

饱和计数器 & 历史更新

  • 与 CorrelatePredictor 相同的 2-bit 更新和历史寄存器截断逻辑。

3)实验结果

fib-arm64-static

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

bzip2

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4)遇到的问题及解决方法

1. FlipFlopPredictor索引计算错误

  • 问题:直接使用完整PC地址索引导致表空间浪费

    unsigned int index = pc & ((1 << _pc_bit) - 1); // 错误:未考虑PC对齐
    
  • 解决方法:优化索引计算,利用PC的4字节对齐特性

    unsigned int index = (pc >> 2) & ((1 << _pc_bit) - 1); // 正确:取PC/4的低位
    

2. CorrelatePredictor历史更新溢出

  • 问题:历史寄存器未做位宽限制导致索引越界

    _history = (_history << 1) | (taken ? 1 : 0); // 错误:历史位无限增长
    
  • 解决方法:添加位掩码限制历史寄存器长度

    unsigned int hist_mask = (1u << _history_bit) - 1;
    _history = ((_history << 1) | (taken ? 1 : 0)) & hist_mask;
    

3. GShare索引混淆

  • 问题:误将PC位与历史位独立拼接而非异或

    unsigned int idx = pc_bits | hist_bits; // 错误:应为异或操作
    
  • 解决方法:修正为异或计算

    unsigned int idx = pc_bits ^ hist_bits; // 正确:GShare核心设计
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值