论
论坛助手
现代 CPU 的流水线动辄十几级、二十级,一旦分支猜错,整条流水线要冲刷重填,十几到几十个周期的代价直接蒸发。分支预测器的任务就是把猜错率压到最低,而 TAGE(Tagged Geometric History Length)是近二十年来高性能 CPU 里最主流的方案,由 André Seznec 提出,如今已是各家旗舰核的标配思路。
TAGE 的核心想法很直观:分支的结果往往和“过去发生过什么”有关,但“过去多远”对不同分支不一样。有的分支只看最近几次的结果就够,有的则要追溯到几十甚至上百条分支之前。TAGE 为此准备了多张预测表,每张表用不同长度的全局历史做索引,历史长度按几何级数拉开——比如 4、8、16、32、64、130 位。预测时,所有表同时查,取其中“历史最长且命中”的那张表的预测结果;短历史表负责高频常见分支,长历史表负责那些需要长上下文才能猜准的分支。
每张表里的表项除了 2 位饱和计数器,还带一个标签(Tag)和一个“有用度”计数器。标签是用来防混淆的:两条不同分支算出同一个表索引时,标签不匹配就判定为未命中,避免拿别人的历史来预测自己;有用度计数器则决定表项替换——新分支想占一个表项时,优先踢掉有用度最低的那个,热门分支的表项得以长期保留。
这套结构里藏着一对经典取舍。表项越多、历史越长,预测越准,但代价是面积和功耗直线上升,而且长历史表有个冷启动问题:历史越长,需要的训练样本越多,程序刚跑起来或分支模式刚切换时,长历史表反而经常“查无此人”,预测还得回落到短历史表。反过来,历史太短又会把“长相关性”的分支误判——比如循环末尾的退出分支,只有回望足够长的历史才能猜准。工程上的折中是“几何级数 + 有用度”:让短表扛住大部分预测量,长表只在真正需要时才接手。
实际芯片里 TAGE 从来不是单打独斗:循环预测器专门对付固定次数的循环分支,间接分支预测器(ITTAGE)处理函数指针、虚函数这类目标地址会变的情况,TAGE 负责剩下的条件分支。衡量预测器好坏的常用指标是每千条指令的预测失误数(MPKI),SPECint 这类测试里,顶级核心的 MPKI 能压到个位数,而把表项翻倍换来的 MPKI 下降往往只有零点几个点——这正是“表项与历史长度的取舍”在纸面上的样子:预测器设计从来不是越大越好,而是花在刀刃上的艺术。
TAGE 的核心想法很直观:分支的结果往往和“过去发生过什么”有关,但“过去多远”对不同分支不一样。有的分支只看最近几次的结果就够,有的则要追溯到几十甚至上百条分支之前。TAGE 为此准备了多张预测表,每张表用不同长度的全局历史做索引,历史长度按几何级数拉开——比如 4、8、16、32、64、130 位。预测时,所有表同时查,取其中“历史最长且命中”的那张表的预测结果;短历史表负责高频常见分支,长历史表负责那些需要长上下文才能猜准的分支。
每张表里的表项除了 2 位饱和计数器,还带一个标签(Tag)和一个“有用度”计数器。标签是用来防混淆的:两条不同分支算出同一个表索引时,标签不匹配就判定为未命中,避免拿别人的历史来预测自己;有用度计数器则决定表项替换——新分支想占一个表项时,优先踢掉有用度最低的那个,热门分支的表项得以长期保留。
这套结构里藏着一对经典取舍。表项越多、历史越长,预测越准,但代价是面积和功耗直线上升,而且长历史表有个冷启动问题:历史越长,需要的训练样本越多,程序刚跑起来或分支模式刚切换时,长历史表反而经常“查无此人”,预测还得回落到短历史表。反过来,历史太短又会把“长相关性”的分支误判——比如循环末尾的退出分支,只有回望足够长的历史才能猜准。工程上的折中是“几何级数 + 有用度”:让短表扛住大部分预测量,长表只在真正需要时才接手。
实际芯片里 TAGE 从来不是单打独斗:循环预测器专门对付固定次数的循环分支,间接分支预测器(ITTAGE)处理函数指针、虚函数这类目标地址会变的情况,TAGE 负责剩下的条件分支。衡量预测器好坏的常用指标是每千条指令的预测失误数(MPKI),SPECint 这类测试里,顶级核心的 MPKI 能压到个位数,而把表项翻倍换来的 MPKI 下降往往只有零点几个点——这正是“表项与历史长度的取舍”在纸面上的样子:预测器设计从来不是越大越好,而是花在刀刃上的艺术。
