跳转至

tage 测试

源代码

/nfs/home/yanyue/tools/nexus-am-xs/tests/cputest/tests/tage2.c https://github.com/OpenXiangShan/nexus-am/blob/master/tests/frontendtest/tests/tage2.c

#include "common.h"

void __attribute__ ((noinline)) branch_test(int cnt) {
    int tmp = 0;
    // 设计一个需要更长历史的分支模式:
    // 使用t2的多个位来决定分支方向
    // 比如:当t2的bit[2:0]为111=7时不跳转,其他情况都跳转
    // 修改后的分支模式:
    #define ONE \
    "andi t3, t2, 7\n\t"    /* 取低3位 */ \
    "li t4, 7\n\t"          /* 目标值111 */ \
    "bne t3, t4, 2f\n\t"     /* 如果不等于111则跳转 */ \
    "nop\n\t" \
    "2:\n\t"

    asm volatile(
    // 初始化计数器
    "li t0, 0\n\t"      // 循环计数器
        "li t2, 0\n\t"      // 模式计数器
        ".align 4\n\t"
        "1:\n\t"
        // 重复执行分支指令
        TEN                  // 每次循环执行10次分支指令
        "addi t2, t2, 1\n\t" // t2每次加1
        "addi t0, t0, 1\n\t" // 增加循环计数器
        "blt t0, %1, 1b\n\t" // 循环控制
        : "+r"(tmp)
        : "r"(cnt)
        : "t0", "t2", "t3", "t4", "memory"
        );
}

int main() {
    branch_test(1000);  // 执行1000次循环
    return 0;
}

反汇编

    80000130:   0073fe13            and t3,t2,7
    80000134:   4e9d                    li  t4,7
    80000136:   01de1363            bne t3,t4,8000013c <branch_test+0x1c>
    8000013a:   0001                    nop
    8000013c:   0073fe13            and t3,t2,7
    80000140:   4e9d                    li  t4,7
    80000142:   01de1363            bne t3,t4,8

主要起始地址为130,

136 的分支,7次taken, 1次NT

1000个循环中,有128个循环都是NT,每个循环有10个branch, 说明至少1280次NT, 这些分支一定需要用tage 来预测。剩下的taken 情况,用uftb 的简单方向预测就能命中,tage 都不用纠正它,也就不会更新tage了

stats.txt

system.cpu.numBranches                          11021
system.cpu.ipc                               2.428763 
system.cpu.commit.branchMispredicts                30 
# 
system.cpu.branchPred.predsOfEachStage::0        10878                       # the number of preds of each stage that account for final pred (Count)
system.cpu.branchPred.predsOfEachStage::1          238                       # the number of preds of each stage that account for final pred (Count)
system.cpu.branchPred.predsOfEachStage::2            0   

# 主要看tage update 部分统计
system.cpu.branchPred.tage.bank_0.updateTableHits::samples         1815                       # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::mean     0.812121                       # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::stdev     1.047108                       # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::underflows            0      0.00%      0.00% # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::0         1077     59.34%     59.34% # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::1          122      6.72%     66.06% # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::2          496     27.33%     93.39% # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::3          120      6.61%    100.00% # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::overflows            0      0.00%    100.00% # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::min_value            0                       # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::max_value            3                       # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateTableHits::total         1815                       # hit of each tage table on update (Count)
system.cpu.branchPred.tage.bank_0.updateNoHitUseBim          128                       # use bimodal when no hit on update (Count)
system.cpu.branchPred.tage.bank_0.updateUseAlt          140                       # use alt on update (Count)
system.cpu.branchPred.tage.bank_0.updateUseAltCorrect          133                       # use alt on update and correct (Count)
system.cpu.branchPred.tage.bank_0.updateUseAltWrong            7                       # use alt on update and wrong (Count)

其中发现tage 预测了1800次,其中60% 都在T0 命中,剩下的其他级命中

而useAlt 基表的情况只有140次,且基本都正确

关注debug-flags=FTBTAGE

./build/RISCV/gem5.debug  --outdir=debug/tage2 --debug-flags=FTBTAGE --debug-file=tage2.tage --debug-end=1000000 ./configs/example/kmhv3.py --generic-rv-cpt=/nfs/home/yanyue/tools/nexus-am-xs/tests/cputest/build/tage2-riscv64-xs.bin --raw-cpt

先看预测阶段

 968364: system.cpu.branchPred.tage: [c: 2908] table 3, index 353, lookup tag 223, tag 213, useful 0, counter -1, v 1, match 0
 968364: system.cpu.branchPred.tage: [c: 2908] table 2, index 871, lookup tag 134, tag 134, useful 0, counter 3, v 1, match 1
 968364: system.cpu.branchPred.tage: [c: 2908] lookup startAddr 0x80000130 cond 0, provider_counts 1, main_table 2, main_table_index 871, use_alt 0

对于130 开头的第一个136 branch, 能看到这里命中到了table2, 其实发现对应的useflu=0?

2555775: system.cpu.branchPred.tage: [c: 7675] table 3, index 353, lookup tag 213, tag 213, useful 1, counter -4, v 1, match 1
2555775: system.cpu.branchPred.tage: [c: 7675] lookup startAddr 0x80000130 cond 0, provider_counts 1, main_table 3, main_table_index 353, use_alt 0

这里命中表3, ixd=353, 对应的useful=1, 合理,要比较晚才更新对useful=1吧

再看更新阶段

先看后期稳定状态的情况了,已经7800拍之后了

2613384: system.cpu.branchPred.tage: [c: 7848] update startAddr: 0x80000130
2613384: system.cpu.branchPred.tage: [c: 7848] try to update cond 0 
2613384: system.cpu.branchPred.tage: [c: 7848] prediction provided by table 3, idx 353, updating corresponding entry
2613384: system.cpu.branchPred.tage: [c: 7848] useful bit set to 1
2613384: system.cpu.branchPred.tage: [c: 7848] squashType 0, squashPC 0x555a9c67e280, slot pc 0x80000136
2613384: system.cpu.branchPred.tage: [c: 7848] this_cond_mispred 0, use_alt_on_main_found_correct 0, needToAllocate 0

在后期发现table3,idx353, 更新useful=1. 并且更新pc 就是136 这条分支指令。

同时没有错误预测,也不需要分配新的表项了。

再看看初期更新状态:第一次更新

 639360: system.cpu.branchPred.tage: [c: 1920] update startAddr: 0x80000130
 639360: system.cpu.branchPred.tage: [c: 1920] try to update cond 0 
 639360: system.cpu.branchPred.tage: [c: 1920] prediction provided by base table idx 152, updating corresponding entry
 639360: system.cpu.branchPred.tage: [c: 1920] squashType 2, squashPC 0x80000136, slot pc 0x80000136
 639360: system.cpu.branchPred.tage: [c: 1920] this_cond_mispred 1, use_alt_on_main_found_correct 0, needToAllocate 1
 639360: system.cpu.branchPred.tage: [c: 1920] allocate new entry
 639360: system.cpu.branchPred.tage: [c: 1920] found allocatable entry, table 0, index 103, tag 155, counter -1

第一次发现是base 表给出的预测结果,idx152. 同时base预测错误(实际NT, 预测为T)

尝试分配新的一项,在T0 这里分配了一个表项,idx103

 653679: system.cpu.branchPred.tage: [c: 1963] update startAddr: 0x80000130
 653679: system.cpu.branchPred.tage: [c: 1963] try to update cond 0 
 653679: system.cpu.branchPred.tage: [c: 1963] prediction provided by base table idx 152, updating corresponding entry
 653679: system.cpu.branchPred.tage: [c: 1963] squashType 2, squashPC 0x80000136, slot pc 0x80000136
 653679: system.cpu.branchPred.tage: [c: 1963] this_cond_mispred 1, use_alt_on_main_found_correct 0, needToAllocate 1
 653679: system.cpu.branchPred.tage: [c: 1963] allocate new entry
 653679: system.cpu.branchPred.tage: [c: 1963] found allocatable entry, table 3, index 1894, tag 230, counter 0

第二次又发现tage 中base 152 预测错误(实际T, 预测NT),直接分配了T3 的表项,lfsr随机生成的位置

 663336: system.cpu.branchPred.tage: [c: 1992] update startAddr: 0x80000130
 663336: system.cpu.branchPred.tage: [c: 1992] try to update cond 0 
 663336: system.cpu.branchPred.tage: [c: 1992] prediction provided by table 0, idx 103, updating corresponding entry
 663336: system.cpu.branchPred.tage: [c: 1992] useful bit set to 0
 663336: system.cpu.branchPred.tage: [c: 1992] use_alt_on_provider_weak, alt correct, updating use_alt_counter
 663336: system.cpu.branchPred.tage: [c: 1992] squashType 2, squashPC 0x80000136, slot pc 0x80000136
 663336: system.cpu.branchPred.tage: [c: 1992] this_cond_mispred 1, use_alt_on_main_found_correct 0, needToAllocate 1
 663336: system.cpu.branchPred.tage: [c: 1992] allocate new entry
 663336: system.cpu.branchPred.tage: [c: 1992] found allocatable entry, table 3, index 153, tag 74, counter 0

第三次发现tage T0 103表项预测错误,useful 改成0,同时直接分配T3 153表项。

此时T0 103, T3 153(t74) 都共存, 接下来立刻预测tage 表项时候发现, 索引了T0 103, 当时历史不同,索引到的T3 143? 而不是T3 153?

 666666: system.cpu.branchPred.tage: [c: 2002] table 3, index 143, lookup tag 155, tag 0, useful 0, counter 0, v 0, match 0
 666666: system.cpu.branchPred.tage: [c: 2002] table 2, index 879, lookup tag 196, tag 0, useful 0, counter 0, v 0, match 0
 666666: system.cpu.branchPred.tage: [c: 2002] table 1, index 1892, lookup tag 248, tag 0, useful 0, counter 0, v 0, match 0
 666666: system.cpu.branchPred.tage: [c: 2002] table 0, index 103, lookup tag 155, tag 155, useful 0, counter 0, v 1, match 1
 666666: system.cpu.branchPred.tage: [c: 2002] lookup startAddr 0x80000130 cond 0, provider_counts 1, main_table 0, main_table_index 103, use_alt 1

更新生成索引153 时候,buf=pc>>1 = 130>>1=0x98, updateIndexFoldedHist=1, index=0x98^1 = 0x99=153

预测生成索引143 时候,indexFoldedHist=0x17, index=0x98^0x17=0x8f=143. 本质上是索引的折叠历史不同。那为何索引T0 时候历史相同呢?应该要看折叠历史的生成过程

第一次更新索引,用的是meta->indexFoldedHist, 也就是上次预测时候的历史。然后再次预测时候,预测历史已经不同了(推测更新了),所以历史不同;而T0的预测历史,本身历史范围小,所以两次预测历史相同,生成的索引历史也相同?再确认下

111111111111111
 660672: system.cpu.branchPred.tage: [c: 1984] getTageIndex pc 0x80000130, t 0, indexFoldedHist 255
 660672: system.cpu.branchPred.tage: [c: 1984] table 0, index 103, lookup tag 155, tag 155, useful 0, counter -1, v 1, match 1
 660672: system.cpu.branchPred.tage: [c: 1984] lookup startAddr 0x80000130 cond 0, provider_counts 1, main_table 0, main_table_index 103, use_alt 0
111111111111011
 663003: system.cpu.branchPred.tage: [c: 1991] getTageIndex pc 0x80000130, t 0, indexFoldedHist 247
 663003: system.cpu.branchPred.tage: [c: 1991] table 0, index 111, lookup tag 131, tag 0, useful 0, counter 0, v 0, match 0
 663003: system.cpu.branchPred.tage: [c: 1991] lookup startAddr 0x80000130 cond 0, provider_counts 0, main_table -1, main_table_index -1, use_alt 1
10111111111111
 666666: system.cpu.branchPred.tage: [c: 2002] getTageIndex pc 0x80000130, t 0, indexFoldedHist 255
 666666: system.cpu.branchPred.tage: [c: 2002] table 0, index 103, lookup tag 155, tag 155, useful 0, counter 0, v 1, match 1
 666666: system.cpu.branchPred.tage: [c: 2002] lookup startAddr 0x80000130 cond 0, provider_counts 1, main_table 0, main_table_index 103, use_alt 1

能看出对于T0, 他在预测时后,indexFoldedHist 变化过255->247->255

本质原因是全局历史从8个1,变成011, 又变回8个1了,不同的全局历史产生不同的index 索引,进而影响到不同表项。对于低级表,其历史只会关注全局历史低部分位,关注历史长度有限。