Bingo (2019 HPCA): Bingo Spatial Data Prefetcher
这篇论文提出的是 Bingo Spatial Data Prefetcher (2019 HPCA):一种基于 Per-Page History (PPH) 的空间数据预取器,用 TAGE 思想把一个 page 的 footprint 同时关联到多个”事件(event)”上,但把所有事件的元数据折叠到同一张 history table 中。
TLDR:
- 现有空间预取器(SMS/SFP/AMPM/VLDP/SPP/BOP 等)把 page footprint 只绑定到 单一 event:长事件(如
PC+Address)准确但不常触发,短事件(如Offset)常触发但不准。鱼和熊掌不可兼得。 - Insight:借鉴 TAGE,把每个 footprint 同时关联到多个事件(长+短),查找时先用最长事件,miss 后逐级退到更短事件,从而同时得到高 accuracy 和高 coverage。
- 观察到 TAGE 的级联多表存储开销大、冗余高(两级 table 预测相同的情况占 26%–93%)。Bingo 把所有事件的 metadata 合并到 一张 history table:用 短事件的 hash 做 index,长事件的位做 tag,使得同一份 footprint 只存一次即可被长、短事件查到。
- 在 ChampSim 上评估,Bingo 相比 no-prefetcher 带来平均 60% 性能提升(最高 285%),比最好的前序空间预取器(SMS)再高 11%(最高 67%),只占 LLC 容量的 6%。
背景和动机
空间数据预取(Spatial Data Prefetcher)
应用访问内存时,数据对象(结构体、数组元素)通常按固定 layout 布置,导致 access pattern 在 page(几 KB 的连续区域)粒度上重复出现。Spatial prefetcher 利用这个 spatial correlation,对每个 page 记录一张位图(footprint)表示该 page 中哪些 block 被访问,再把 footprint 绑定到某个 event,下次同一 event 再现时就直接按 footprint 发起预取。
空间预取器相比 temporal 预取器的几大优点:
- 存储 offset/delta 即可,不用存整条地址流,metadata 小得多
- 可预取 compulsory miss(footprint 可迁移到未访问过的新 page)
- 能把一个 DRAM row 里的 block 一次性取出,减少 DRAM row activation,对能效友好
两类空间预取器
- SHared History (SHH): 全局共享的 delta/pattern 表。例:BOP、SPP、VLDP。优点是存储紧凑;缺点是不同 page 的行为被糅到一起,在行为差异大的 workload 上 coverage 低;而且多 degree 预取容易产生大量 overprediction。
- Per-Page History (PPH): 为每个 page 记 footprint,page 结束时将
<event, footprint>存入 history table。例:SFP(PC+Address)、SMS(PC+Offset)、AMPM。优势是一次就能把整张 footprint 发出,timeliness 好、coverage 高。
Bingo 属于 PPH 路线。
核心痛点:单一 event 的两难
作者对比了 5 种 event 的 accuracy 与 match probability(图 2):
| Event (从长到短) | Accuracy | Match Probability |
|---|---|---|
PC+Address |
最高 (~90%) | 很低 (~50%) |
PC+Offset |
高 | 中 |
Address |
中 | 中 |
PC |
较低 | 较高 |
Offset |
最低 (~50%) | 最高 (>75%) |
长事件 = 多个具体事实同时发生(指令 + 地址),短事件 = 只需一个事实。长事件准但不常;短事件常但不准。只选一个,必定牺牲 coverage 或 accuracy。
Insight
把一个 page 的 footprint 同时关联到”多个长度不同的事件”上(即 TAGE-like 思想在 prefetcher 上的应用):
- 预取时先用最长事件查(最准),找不到再退到次长事件、再短事件……
- 实验证明从 1 个 event 扩到 2 个 event(
PC+Address+PC+Offset),coverage 有质的飞跃;扩到 5 个事件收益饱和。因此 Bingo 只用 2 个事件即可。
但原生 TAGE-like 方案需要多张级联 history table,存储开销大,而且这些表的预测存在大量冗余(两表同样预测的情况在 benchmark 上最高达 93%,平均明显)。
核心设计
Bingo 的核心设计一句话:一个 page 的 footprint 被同时绑定到长事件 PC+Address 和短事件 PC+Offset,但只存一份;用一张 history table,通过两次查找覆盖两个事件。
- Auxiliary Table(辅助存储,记录正在 active 的 page 的 footprint)
- History Table(训练完成后的 footprint 存放处,统一单表)
- 核心诀窍:用短事件
PC+Offset的 hash 作 index,用长事件PC+Address的全位作 tag - 查找流程:先按
PC+Addresstag 匹配 → 若不中,再比较同 set 中其他表项的PC+Offset位是否匹配 → 若多个匹配,取若干 footprint 聚合(某 block 在 ≥20% 匹配项中出现就预取它)
1. Auxiliary Storage(追踪 active pages,实为两级)
论文只笼统地称 “auxiliary storage”,开源实现里它其实被拆成两张表以节省面积并过滤”只访问一次就结束”的 page:
1.1 FilterTable(FT)
- 规模:64 项,全相联 LRU。
- 每项存:
region_number(key) + 首次访问的<PC, offset>。 - 作用:一个 page 第一次被触达时登记在 FT 里;若这个 page 自始至终只被访问过同一个 offset(即”一次性 scan”),它不会被 promote 到 AT,也就不会污染 PHT。
1.2 AccumulationTable(AT)
- 规模:128 项,全相联 LRU。
- 每项存:触发访问的
<PC, offset>+ 长度为pattern_len的位图(vector<bool>)。 - 进入条件:FT 中的 page 再被访问到一个不同的 offset 时,把 FT 项”升格”到 AT 并开始累积 footprint;FT 中的同一项同时擦除。
- 退出条件:该 page 被 LLC evict(收到
eviction()回调)→ 将<trigger PC+Address, footprint>写入 PHT。
开源里的
access()每次 LLC 访问都会调用:先查 AT(命中则仅置位),再查 FT。这与论文正文描述一致,但双表结构在论文图里没有突出体现。
2. History Table(PHT):单表 + TAGE 风格双查
- Index:由一个 CRC-式折叠函数从”key”产生。Key 的布局是
base | PC | offset(高位到低位),然后用tag = PC|offset反复右移index_len位并 XOR 折叠回 key 的低index_len位,得到最终 set index。 - Tag:整条 key(包含 base/PC/offset 全部有效位)在选中 set 后整体做比较。
- 两种匹配(通过两个 mask 同时检查):
max_tag_mask = (1 << (PC_WIDTH + MAX_ADDR_WIDTH - index_len)) - 1→ 等价于PC+Address全匹配(称max_match)。min_tag_mask = (1 << (PC_WIDTH + MIN_ADDR_WIDTH - index_len)) - 1→ 只比较PC + offset部分(称min_match),即PC+Offset。
- 查找优先级:遍历该 set 的所有 way,一旦出现
max_match就立即采用其 pattern,记last_event = PC_ADDRESS;否则把所有min_match的 pattern 收集起来投票,记last_event = PC_OFFSET。 - Pattern 旋转:存入 PHT 前 pattern 会按
-offset旋转归一(使 trigger offset 在位 0),查出时再按+offset还原。这样不同 offset 触发但形状相同的 footprint 可以共享同一条 PHT 表项,显著提升命中率——这是论文正文没强调的一个实现细节。 - 投票阈值:
#define THRESH 0.20。被 ≥20% 的 min-match 条目在同一位置置位的 block 才会进入 prefetch 列表。代码里还提供了bingo_thresh001…bingo_thresh100等变体用于灵敏度研究。
存储配置(与源码常量对齐)
开源实现 prefetcher/bingo.llc_pref 末尾的硬编码常量:
| 常量 | 值 | 含义 |
|---|---|---|
REGION_SIZE |
2048 B | page / region 大小(= 32 × 64B block;注意论文正文的”几 KB 的 page”在代码里就是 2KB) |
MIN_ADDR_WIDTH |
5 bit | offset 宽度(对应 32 个 block 需 5 位) |
MAX_ADDR_WIDTH |
16 bit | address 字段使用的总宽度(含 base + offset) |
PC_WIDTH |
16 bit | PC 截取宽度 |
PHT_SIZE |
16 K 项 | PHT 总条目(默认 16-way → 1024 set,index_len = 10) |
FT_SIZE |
64 项 | FilterTable |
AT_SIZE |
128 项 | AccumulationTable |
THRESH |
0.20 | min-match 投票阈值 |
PHT 每项含 valid / LRU / tag(~27 bit) / 32 位 footprint。总大小约 119 KB ≈ LLC 的 6%。灵敏度分析表明 16K 项后 coverage 饱和。
代码解读(基于作者开源 ChampSim 实现)
开源地址: https://github.com/bakhshalipour/Bingo
关键源文件 prefetcher/bingo.llc_pref(795 行,单文件自包含;inc/ 里没有头文件依赖)。仓库还包含 sms.llc_pref / bop.llc_pref / spp.llc_pref / vldp.llc_pref / ampm.llc_pref 以及 bingo_01k … bingo_64k、bingo_thresh001 … bingo_thresh100、bingo_multitable_*(用于 TAGE 级联表对比)、bingo_plus 等变体,正好对应论文的几组灵敏度/消融实验。
1. 模块组织
1 | SetAssociativeCache<T> |
所有表都自带一个 per-set CAM (unordered_map<tag, way>),使得 find() 不用线性扫描整个 set——这只是模拟器的便利写法,硬件上依然是并行 tag 比较。
2. 主流程 Bingo::access(block_number, pc)
对每一次到达 LLC 的访问执行:
1 | region_number = block_number / pattern_len // pattern_len = 32 |
要点:
- 只有 trigger access 会向 LLC 发 prefetch;后续同一 page 的访问只是更新位图。
- 只”来过一次 offset”的 page 永远不会进入 AT,避免污染 PHT(这是一种隐式过滤)。
- AT 满时 LRU victim 会立即训练 PHT,不必等待 eviction 回调——对于常驻工作集也能持续更新。
3. 何时训练 PHT:两条路径
- AT 满溢出 → 受害 entry 直接
insert_in_phts(在access()中触发)。 - LLC evict 某 block →
Bingo::eviction(block_number)同时擦除 FT/AT 对应 region;若在 AT 里则同时训练 PHT。
所以文字描述的”page 结束 residency 后训练”其实更精确地是”region 的整张 footprint 从 AT 离开时训练”,无论是被 LRU 挤掉还是被真的 evict。
4. PatternHistoryTable::build_key —— CRC 折叠
1 | key_raw = (base << (PC_WIDTH + MIN_ADDR_WIDTH)) |
这段循环把 PC|offset 不断右移 index_len 位并 XOR 进 key 的低 index_len 位;等价于对 PC+Offset 的一次 CRC-like 哈希,只不过与 base 拼接后再按 set_mask 取模选 set。效果:set index 由 hash(PC+Offset) 决定,tag 仍为 PC+Address(隐式包含 PC+Offset)。这完美对应论文”短事件 index + 长事件 tag”的设计。
5. PatternHistoryTable::find —— max/min 匹配与投票
1 | for each valid way in set: |
三个细节与论文图示有出入:
- 所有候选 pattern 平权投票,
THRESH=0.20是硬编码,没用 recency 加权(论文脚注 7 说明作者测试过 recency,最终选阈值法)。 max_match命中后会set_mru(key),但min_match投票时不更新 LRU——只有成功预测的长事件项会续命,短事件项更易被淘汰。- 因
MAX_ADDR_WIDTH > MIN_ADDR_WIDTH,max_tag_mask ⊇ min_tag_mask,所以max_match ⇒ min_match;代码用break保证 max 优先。
6. Pattern 旋转归一
1 | // insert: |
trigger offset 总是被归一化到 bit 0 才存入 PHT。论文正文未强调这点,但它对 coverage 很重要:同一个 PC 以不同 offset 触发”相同形状”的 pattern 时(例如扫描 array 时每次从不同元素起步),它们可以共用同一条 PHT 表项。
7. 统计(区分两种事件来源)
代码里 events[region_number] 记录当次预测由 PC_ADDRESS 还是 PC_OFFSET 触发,并在 fill/evict 回调里分别计数 prefetch_cnt / cover_cnt / overpredict_cnt。论文里看不出的经验事实是:作者在开源里还为这两种事件分别统计 coverage 和 overprediction,方便做事后归因(哪部分收益真的来自”短事件兜底”)。
8. 与论文描述的对应关系 / 差异
| 论文描述 | 代码实现 | 备注 |
|---|---|---|
| “auxiliary storage” | FilterTable(64) + AccumulationTable(128) | 两级结构,用 FT 过滤 one-shot page |
| “page 结束时训练 PHT” | AT 满溢出 或 LLC evict 时训练 | 两条路径 |
| “hash(PC+Offset) 索引, PC+Address tag” | CRC-style fold;tag 用 max/min 双掩码 | 完全一致 |
| “20% 阈值” | #define THRESH 0.20 |
硬编码;提供 001…100 变体 |
| “LRU 替换” | Super::set_mru / select_victim | 只在 max_match 和 insert 时续命 |
| 论文未提 | pattern 按 offset 旋转归一 | 提升跨 offset 泛化能力 |
| 论文未提 | AT 溢出也训练 PHT | 常驻 page 也能持续更新 |
实验 Setup
实验平台:ChampSim(DPC-2 的基础设施)
Workload 选择:
- 服务器级 big-data workload:Data Serving、SAT Solver、Streaming、Zeus、em3d
- 5 个 SPEC 混合(Mix 1–Mix 5,每个 4 个内存密集 SPEC program)
- 服务器负载用 SimFlex 方法,从 warmed checkpoint 跑 200K insns(其中 40K 填 ROB/队列,后续测量),95% 置信、<4% 误差
- SPEC:每核跑 ≥100M insns,前 20M warmup,之后 80M 测量
系统设置:
- 14nm、4GHz、4 核(4-wide OoO, 256-entry ROB, 64-entry LSQ)
- L1 D/I:各 64KB,8-way, 4-cycle,8 MSHR
- L2(= LLC):8MB,16-way,4-bank,15 cycle hit
- 主存:60 ns,37.5 GB/s,2 通道
- 每核独立 prefetcher(核间不共享 metadata),所有方法触发于 LLC 访问并直接 prefetch 到 LLC
对比对象(均做 sensitivity 调到合理 coverage):
- BOP(DPC-2 冠军,256-entry RRT)
- SPP(256 Signature / 512 Pattern / 1024 Prefetch Filter)
- VLDP(16 DHB / 64 OPT / 3×64 DPT)
- AMPM(表扩到 LLC 全容量)
- SMS(16K-entry, 16-way,Bingo 的基座)
- Bingo(16K-entry, 16-way)
实验结果
实验 1:存储灵敏度
设计:改变 Bingo 的 history table 大小(1K→64K)观察 miss coverage。
结果:miss coverage 随 size 增加而上升,16K 项后进入平台期。
结论:Bingo 固定 16K 项 / 119KB(LLC 的 6%),在容量和 coverage 间取得最佳平衡。
实验 2:miss coverage & overprediction
设计:比较所有方法 covered / uncovered / overprediction(错预取数 / baseline 的 miss 数)。
结果:
- Bingo 平均 coverage >63%,比第二名高 8%
- Overprediction 与其它主流预取器相当,无显著恶化
- SHH 类(BOP/SPP/VLDP)在服务器负载上 coverage 显著偏低;VLDP 多 degree 预取带来不准
- PPH 类(AMPM/SMS)coverage 较高但 Bingo 仍领先
结论:多事件关联 + 最长事件优先匹配 的确能同时把 accuracy 和 opportunity 吃满。
实验 3:系统性能
结果:
- 相对 no-prefetcher,Bingo 平均 +60%,最高 +285%(em3d)
- 对 SMS 再提升 +11%,最高 +67%
- Zeus 上提升仅 11%,因该 workload 更偏 temporal correlation,OoO 已覆盖大多数 spatial miss
结论:Bingo 在各种 workload 上一致领先,timeliness(一次性发出整页需要的 block)+ multi-event 匹配 是关键。
实验 4:Performance density(单位面积性能)
设计:计算每种方案”性能提升 / 芯片面积”,衡量硅利用效率。
结果:Bingo 的 performance density 比 baseline 高 59%,比第二名高 10%。面积开销 < LLC 的 6%,导致 density 相对 performance 只掉 <1%。
结论:哪怕把 prefetcher 面积的机会成本计入,Bingo 也是”划算”的设计。
实验 5:ISO-degree 比较
设计:解开 SHH 方法的 degree 限制(BOP/VLDP → 32,SPP 门槛 → 1%),让它们也尝试多发预取以追平 PPH 的 timeliness。
结果:SHH 系方法性能略升但 overprediction 大幅增加(VLDP overpred 从 14% 涨到 31%;SPP 从 25% 涨到 286%!)。Bingo 仍明显领先。
结论:SHH 类方案即使被允许”激进发射”,其数据结构本质不知道一页到底还需要多少块,因此无法在不污染带宽的前提下达到 Bingo 的 timeliness。
Limits
- 两事件已够用? 论文自述 event 数增至 5 时收益饱和,因此仅用 2 个。但这个饱和结论建立在一个选定的事件集合之上(
PC+Address / PC+Offset / Address / PC / Offset),未必对其他 workload 成立。 - 短事件撞 set 时的融合策略比较简陋:20% 阈值为经验值,作者只对比了 “recency” 等少数替代。当集合内匹配条目的 footprint 差异大时,融合后可能产生 overfetch 或 underfetch。
- 仍然是 PPH 范式:每个 page 都需 auxiliary storage 跟踪,对超大 working set 或扫描型 workload 的 active-page 并发量仍有限制(虽然 auxiliary 存储本身不大)。
- 依赖 page residency 信号训练:footprint 只在 page 结束 residency 时才被提交到 history table。若 page 长时间驻留,训练样本产生滞后,对新 pattern 的收敛会慢。
- 跨核/多线程共享未探索:本文每核独立 prefetcher,未考察服务器多租户场景下 PC 别名与共享数据的干扰。
- 相关替代思路未对比:IMP、TEMPO、Domino、B-Fetch 等走 indirect / temporal / 分支-驱动路线,与 Bingo 正交。Bingo 没有与这些做叠加实验。