Champsim Cache
坐标:: cache.h
, cache.cc
class::CACHE
构造
构造函数:CACHE::CACHE(champsim::cache_builder<>)
,由全局 env 通过 cache_builder 初始化
cache_builder
模板类,需要的typename P 和 R 均继承自 cache_builder_module_type_holder。其中,P 代表 prefetcher,R 代表 replacement,通过模板的偏特化函数选择相应的类。
成员
upper_levels/lower_level:
上/下级 cache 接口,channel_type(接口协议类)。对于 L1 Cache, upper_levers 连接 core 。
lower_translate:
地址转换接口,channel_type。对于 L1Cache 而言,该端口连接 L1TLB;
问题: 为什么 L2Cache 的该端口连接的是 L2 TLB?# ; LLC 的该端口留空。
MAX_TAG:
每个周期最多可以同时接受几个 tag 访问请求,对于多端口 cache 而言,MAX_TAG > 1
MAX_FILL:
每个周期最多可以同时接受几个 refill 响应,取决于总线协议
inflight_tag_check:
在飞的tag比较请求队列。每个周期开始时,会先从 translation_stash 中取出完成转换的请求,然后从上级 cache 中取出可以进行地址转换的请求,但是每个周期能取到的请求总数限制于 initiate_tag_bw 带宽之下。
translation_stash:
地址转换请求的暂存队列
pref_module_pimpl / repl_module_pimpl:
预取器、替换策略的物理实现
成员类
- 请求类
- tag 查找请求 :
tag_lookup_type
- mshr 请求 : mshr_type
- tag 查找请求 :
- 子系统类
- 预取器
prefetcher_module_concept
- 替换策略
replacement_module_concept
- 预取器
- mshr_type
用于访问和处理
data_promise:
waitable 对象,下级 cache 返回数据后被赋值。当赋值完成的 cycle 到来时会被调入 handle_fill 处理
operable 接口实现
- initialize()
- 预取器初始化:
impl_prefetcher_initialize()
,直接调用成员预取器的impl_prefetcher_initialize()
- 替换策略初始化:
impl_initialize_replacement()
,直接调用成员替换策略的impl_initialize_replacement()
- 预取器初始化:
- begin_phase(): 初始化各统计变量
- end_phase(unsigned cpu): 收集并统计最终的各统计变量的结果
- operate()
- 调用所有上级cache 的
check_collision()
- Finish returns : 处理下级 cache 的响应
- 对于下级 cache returned 队列中的每个响应调用 finish_packet
- 计算下级 cache returned 队列中的响应个数累加到 progress
- 清空下级 cache 的 returned 响应队列
- Finish translations : 如果 cache 存在TLB端口, 处理 TLB 返回的结果
- 处理过程同下级 cache
- Perform fills :对于 MSHR 队列和 inflight_writes 队列
- 在 fill_bw 带宽内,每个队列选择所有 data_promise 已准备好的 entry(应当在队列的头部保存所有准备好 fill 的 entry)
- 对 fill 范围的每个请求进行 handle_fill, 遇到第一个 handle 失败的作为结束地址
- 将 handle 成功的请求移出该队列,并消耗相应 fill_bw 带宽
- 计算本周期可以接受的 tag 请求带宽,并将 translation_stash 中完成转换的请求加入 inflight_tag_check 队列
- 计算出当前周期可以接受的新的 tag_check 请求的带宽 : initiate_tag_bw
- 在 initiate_tag_bw 的带宽下,对于 translation_stash 中的请求,如果完成地址转换,将其移入 inflight_tag_check,并消耗相应带宽
- [red]#如果有多个上级 cache,交换这些cache的位置?(看不懂)#
- 将上级 cache 中的 tag 请求,在带宽约束下移入 inflight_tag_check 队列
- 对于上级 cache 的所有请求队列,计算出每个上级cache可以占用的tag带宽
- 在每个上级cache能占用的带宽之下,将请求队列中可以进行地址转换的的请求移入 inflight_tag_check,并消耗相应的 initiate_tag_bw
- 发射地址转换请求 : 对每个请求依次检查是否完成地址转换,若未完成,则通知TLB:
issue_translation()
- 对于 inflight tag check 中的请求而言,是第一次发送地址转换请求
- 对于 translation_stash 中的请求而言,是上一个周期未完成的地址转换请求
- 本周期 inflight_tag_check 中未完成的地址转换请求加入 translation_stash
- Perform tag checks
- 根据目前 inflight tag check 请求找到其中已经完成地址转换的请求得到请求地址范围
- 将这些tag请求依次 try_hit
- 对于 tag 比较结果为 miss 的请求,进行 do_handle_miss
- 消耗相应的 tag_check 带宽 (每次 operate 最大带宽为
MAX_TAG
) - 从 inflight tag check 请求中删除已完成的 tag check 请求
- 调用预取器的
operate()
- 返回消耗的总带宽:包括 下级返回数据和完成地址转换消耗的带宽 + fill消耗带宽 + 初始化tag带宽 + tag check带宽
- 调用所有上级cache 的
- 对于没有设置
m_wq_full_addr
的 write miss , 调用 handle_write 处理请求:此时的请求属于写回miss后的替换block - 对于其他请求,调用 handle_miss
至于 m_wq_full_addr 到底什么意思不太懂?champsim default 设置中 l1cache 均设置了该变量,而 l2 和 llc 均未设置该变量
带宽消耗:
最终 operate() 返回所有操作的请求数:
progress:
包括:
. 下级 cache 每周期响应返回请求数据的个数
. TLB 每周期响应返回请求数据的个数
. 每周期从 inflight_tag_check 移入 translation_stash 的请求数
initiate_tag_bw:
每个周期可以接受的新的 tag 访问请求,用于补充 inflight_tag_check 队列。主要消耗来自:
- 每个周期刚开始 translation_stash 中已完成地址转换的请求
- 上级 cache 中可以进行地址转换的请求
fill_bw:
每周期可以处理的 refill 数量,用于处理 MSHR 队列和 inflight_writes 中的未响应请求
tag_check_bw:
每周期可以访问的 tag 的请求数
CACHE 操作实现
finish_packet()
: 处理下级 cache 返回的数据- 找到 MSHR 队列中地址匹配的 entry , 并将下级 cache 返回的数据和将来完成 fill 的时间打包为 waitable 对象并赋值给其 data_promise
- 找到 MSHR 队列中第一个 data_promise 未赋值(意味着下级 cache 尚未返回该 entry 请求的数据) 的 entry,将地址匹配的 entry 和该entry交换位置,目的是希望所有 data_promise 已完成的 entry 都放到队列的前面以便于处理 refill。
-
- 找到
translation_stash
中未完成地址转换的 entry,从其中找出与 TLB 返回的地址匹配的 entry - 将这些 entry 标记为完成地址转换并将转换后的物理地址写入相应的entry:
mark_translated
- 将 inflight_tag_check 队列中的所有地址匹配的 entry 都
mark_translated
- 找到
handle_fill()
: 根据下级cache返回的数据 refill 当前cache- 根据地址确定要 refill 的 cache set
- 如果该 set 的各个 way 均 valid ,则调用
impl_find_victim
找到要替换的 way ;如果有 way 不是 valid ,优先选该 way 做替换 - 找到要替换的 way 后,如果该 way valid 且 dirty,需写回下级 cache ,
lower_level->add_wq(writeback_packet)
- 通知 prefetcher 和 replacement 此次 refill 的具体信息,便于其更新状态
impl_prefetch_cache_fill
,impl_replacement_cache_fill
- 完成真正的 refill 操作: fill_block 直接赋值给 cache block
- 将 refill 的具体信息打包为 mshr 的 response_type 加入 该 mshr entry 的 to_return 队列
(此时原先 miss 的请求再次 <> 将 hit 并返回数据同时移出 MSHR 队列)
impl_find_victim
,impl_replacement_cache_fill
均由 replament 模块的成员 repl_module_pimpl 实现
try_hit()
: 比较 tag ,检查是否 hit- 根据地址确定要访问 的 cache set, 没找到则 miss
- 更新 prefetcher 和 replacement:
impl_prefetcher_cache_operate
,impl_update_replacement_state
- 如果 hit
- 将响应加入请求 handle_pkt 的 to_return 队列
- 对于写请求,置位 hit block 的 dirty 位
- 如果该 hit block 是预取来的,将 prefetch 位置0
Champsim trace 信息并不包含访问的字节数, cpu 对内存的访问是否 hit 只会通过比较 block_num 和 block_offset 决定,并不会实际返回数据。