预取专用Cache分区计划
目标
为 Cache 增加一个只存放预取行的分区。预取的插入/替换/查询仅在该分区内进行,普通需求行不得占用。需求命中应能正常读取,是否迁移需定义。
现有关键位置
- 访问/命中/未命中与填充逻辑位于 src/mem/cache/base.cc。
- Cache 前端类在 src/mem/cache/cache.hh 及实现 src/mem/cache/cache.cc。
- 标签与组相联实现位于 src/mem/cache/tags/base.hh、src/mem/cache/tags/base_set_assoc.hh、src/mem/cache/tags/base_set_assoc.cc。
- 预取元数据在填充时写入,逻辑在 base.cc 的填充路径。
待确认设计点
1) 分区形态:每组预留若干路 vs 独立标签存储,倾向每组预留路以便接入现有索引。 2) 需求命中是否迁移到主分区,或仅标记“已需求访问”并留在预取分区。 3) 替换策略:预取分区独立策略实例,或复用同一策略但作用于子集路。 4) 容量参数:按路数/字节/比例暴露,支持 0 关闭。 5) 预取分区驱逐与主分区在一致性/写回语义上是否完全相同。
工作步骤
1) 参数面:新增 Cache 参数(开关与分区大小),配置层与 SCons 暴露。
2) 块元数据:扩展 CacheBlk 标记分区驻留与是否被需求提升,覆盖序列化/重置。
3) 标签/组相联分区:在 BaseSetAssoc(或派生)维护主/预取两套替换池;查找覆盖两分区;按分区选牺牲块。
4) 查找路径:BaseCache::access 同查两分区;命中预取分区时的处理与统计拆分。
5) 填充/分配路由:handleFill/allocateBlock 将预取响应路由至预取分区,禁止非预取分配进入;分区满时仅内部驱逐。
6) 提升策略:需求命中预取分区时决定“迁移到主分区”或“原地标记需求”,并更新替换元数据。
7) 驱逐/写回路径:evictBlock、doWritebacks、CleanEvict 保持分区隔离但语义一致,统计独立。
8) 预取队列:确保 MSHR 分配对预取请求打标,便于填充分路由识别;必要时增加断言/计数。
9) 统计/探针:预取分区占用、命中、填充、驱逐、提升、DOA 等计数,必要时调整暖身处理。
10) 配置与文档:更新 Cache.py/PrefetcherConfig.py 等配置,补充用户文档与调优说明。
11) 测试:微基准覆盖仅预取、混合需求+预取、启用分区的 checkpoint/恢复、一致性与失效场景。
风险/关注点
- 替换策略需支持双池。
- 分区化可能影响延迟建模(tag/data 端口计数)。
- 序列化需保留分区与替换状态。
- 默认关闭以确保兼容性。
讨论更新(方案锁定后续步骤)
基于已确认的设计选项: 1) 分区形态:每组预留若干路。 2) 需求命中仅标记“已需求访问”并留在预取分区,不迁移。 3) 替换策略:复用同一替换策略实例,但作用于分区内子集路。 4) 容量参数:按比例暴露,支持 0 关闭。 5) 驱逐语义:预取分区与主分区在一致性/写回语义上完全相同。
下一步工作规划
1) 参数落地:新增比例型分区参数与开关;Python 配置与 SCons 接口同步;默认 0 关闭。
2) 块元数据:为 CacheBlk 增加分区驻留标记与“已需求访问”标志;补齐序列化/重置逻辑。
3) 分区化标签/替换:在 BaseSetAssoc(或派生)实现按组预留路的双分区池,复用同一替换策略实例但限制候选路集;提供按分区选 victim 的接口。
4) 访问路径:BaseCache::access 查两分区;命中预取分区时仅标记“已需求访问”,不迁移;统计分拆。
5) 填充/分配路由:handleFill/allocateBlock 将预取响应放入预取分区;普通需求不得占用;分区满时仅内部驱逐,语义与主分区一致。
6) 驱逐与写回:复用现有写回/一致性流程,但保持分区隔离与统计独立;确保 CleanEvict/Writeback 行为一致。
7) 预取标记链路:确保 MSHR/请求链路对预取打标,便于填充分区路由;缺标时记录计数/告警。
8) 统计:新增占用、命中、填充、驱逐、已需求访问计数(含 DOA),按分区拆分;若使用比例参数,记录实际预留路数。
9) 测试计划:
- 仅预取流:验证预取分区被使用且需求不会进入。
- 混合流:需求命中预取分区仅标记不迁移;容量隔离有效。
- 恢复/一致性:checkpoint/restore,CleanEvict/Writeback 语义一致性。
- 关闭模式:参数为 0 时行为与原先一致。
## 讨论更新(追加)
新的设计点修正:
1) 分区形态:每组预留若干路,按比例参数计算预留路数;向下取整;若不足 1 路则该组预留 0(等价于禁用)。
2) 需求命中:仅标记“已需求访问”,不迁移出预取分区。
3) 替换策略:预取分区使用独立的替换策略实例(与主分区解耦)。
4) 容量参数:按比例暴露,支持 0 关闭;组数若非幂次则报错(仅在参数为幂次组数时工作)。
5) 驱逐语义:预取分区与主分区在一致性/写回上完全一致。
### 下一步工作规划(根据新设计点)
1) **参数实现**:比例型分区参数,向下截断到整路;不足 1 路取 0;若组数非幂次直接报错;默认 0 关闭。配置层与 SCons 同步。
2) **块元数据**:`CacheBlk` 增加分区驻留与“已需求访问”标志,含序列化/重置。
3) **分区化标签/替换**:BaseSetAssoc(或派生)维护主/预取双池,预取池使用独立替换策略实例;按组预留路数由比例计算;victim 选择限定在各自池内。
4) **访问路径**:`BaseCache::access` 查两分区;命中预取分区仅标记已需求访问,不迁移;统计分拆。
5) **填充/分配路由**:`handleFill`/`allocateBlock` 将预取响应放入预取分区,普通需求不得占用;预取分区满时仅内部驱逐,语义与主分区一致。
6) **驱逐与写回**:复用现有流程,保持分区隔离与统计独立,保证 CleanEvict/Writeback 语义一致。
7) **预取标记链路**:MSHR/请求需带预取标记,缺标计数/告警,确保填充分路由正确。
8) **统计**:分区占用、命中、填充、驱逐、已需求访问、DOA;记录比例参数实际转换的预留路数。
9) **测试**:
- 仅预取流:验证预取分区启用与容量隔离。
- 混合流:需求命中不迁移,统计正确。
- 非幂次组数:应触发报错覆盖。
- 关闭模式:参数为 0 时回归旧行为。