










结合 CPU cache 来看,rd / wr / refill 要放在 CPU 核 → L1 → L2 → L3/LLC → 内存 这条路径里理解:
rd:CPU 核发出的读请求,通常来自 load 指令、取指、页表 walker。wr:CPU 核发出的写请求,通常来自 store 指令。refill:cache miss 后,由 cache 控制器把下级或其他核的一整条 cache line 填进当前 cache。它不是 CPU 指令直接发起的,而是 miss 的结果。CPU Core
├─ Load Unit -- rd --> L1D Cache
├─ Store Unit -- wr --> Store Buffer --> L1D Cache
└─ Fetch Unit -- rd --> L1I Cache
L1D/L1I miss
-> L2 Cache
-> L3/LLC
-> Memory
<- refill cache line (常见 64B) <-
关键点:
rd/wr 是 CPU 核/上游对 cache 的访问请求。refill 是 cache miss 后,下级向当前 cache 填充数据。refill 往往表现为一次 rd。以 L1D load 为例:
Load 指令执行
-> AGU 生成虚拟地址
-> TLB 翻译成物理地址
-> 查 L1D tag
-> hit:
从 L1D data array 取出数据
返回 CPU
-> miss:
1. 分配 MSHR,记录这个 miss
2. 向下级 L2 发 rd
3. L2 hit:L2 返回整行
L2 miss:继续向 L3/内存
4. 数据回来后 refill L1D
5. 更新 tag、valid、一致性状态
6. 从 line 中取出 CPU 要的字节/字
7. 唤醒 load,返回 CPU
要点:
rd 的粒度通常是 load 大小,比如 1/2/4/8/16/32 字节。refill 的粒度是 cache line,常见 64 字节。refill 服务多个 rd。以 L1D store 为例:
Store 指令执行
-> 生成地址和数据
-> 进入 Store Buffer
-> 查 L1D tag
-> hit:
如果 write-back:
只写 L1D,置 dirty
如果 write-through:
写 L1D,同时写下级
-> miss:
情况 A:write-allocate,写分配
1. 发 RFO / Read For Ownership
2. 从下级或其他核取得整行和独占权
3. refill L1D
4. 把 store 数据合并进 line
5. 置 dirty
情况 B:no-write-allocate / non-temporal store
1. 不 refill L1D
2. 直接写下级,或进 write-combining buffer
要点:
wr 是 CPU 的写请求。refill。refill:
write-allocate:有 refill,典型是 write-back cache。no-write-allocate:没有 refill。RFO,即先拿到独占权,再写。这个 RFO 可能触发其他核 invalidate,并伴随 cache-to-cache transfer 和 refill。refill 是 cache 控制器行为:
触发:
L1D load miss
L1I 取指 miss
L1D store miss + write-allocate
L2/L3 miss
预取器预取
动作:
1. 当前 cache 向下级发读请求
2. 下级返回一整条 cache line
或者其他核通过 cache-to-cache transfer 返回
3. 写入当前 cache 的 data array
4. 更新 tag、valid
5. 根据一致性协议设置状态:
M / E / S / I 等
6. 如果是写分配,之后还会被 store 写,可能变 dirty
要点:
refill 方向:下级/其他核 → 当前 cache。writeback 方向:当前 cache → 下级,脏行被逐出时发生。refill 和 writeback 方向相反,不要混淆。refill 通常按 cache line 计,不是按 load/store 大小计。| 项目 | rd | wr | refill |
|---|---|---|---|
| 发起者 | CPU load/取指/页表 walker | CPU store | cache 控制器/预取器 |
| 方向 | Core → Cache | Core → Cache | 下级/其他核 → 本 Cache |
| 含义 | 读请求 | 写请求 | miss 后填充整行 |
| 粒度 | 1/2/4/8/16/32B 等 | 1/2/4/8/16/32B 等 | cache line,常见 64B |
| 触发条件 | 读访问 | 写访问 | 通常是 miss |
| 是否一定发生 | 不一定 | 不一定 | 只有需要填充时发生 |
| 与一致性关系 | 读共享 | 写通常要独占/RFO | 填充后状态由协议决定 |
| 典型 PMU 事件 | L1D_CACHE_RD | L1D_CACHE_WR | L1D_CACHE_REFILL |
rd -> L1D hit -> 返回数据
无 refill。
rd -> L1D miss -> 向 L2 发 rd -> L2 返回 line -> refill L1D -> 返回 CPU
有 refill。
wr -> L1D hit -> 写 L1D
write-back:置 dirty
write-through:同时写下级
通常无 refill。
wr -> L1D miss -> RFO -> 取得独占权 -> refill L1D -> 合并写 -> 置 dirty
有 refill,而且常伴随一致性动作。
wr -> L1D miss -> 直接写下级
通常无 L1D refill。
victim dirty -> writeback 到下级
这是 writeback,不是 refill。
多核场景下,L1 miss 不一定只去 L2/内存:
Core0 L1D miss
-> L2/LLC 查询
-> 发现 Core1 L1D 有 Modified 数据
-> snoop Core1
-> Core1 把数据直接传给 Core0
-> Core0 refill L1D
所以 refill 的来源可能是:
写 miss 更复杂,因为要拿所有权:
Core0 store miss
-> 发 RFO
-> 其他核 invalidate 对应 line
-> Core0 取得独占权
-> refill 或直接合并数据
-> 写 L1D,置 Modified
在 CPU cache 里:
rd 是 CPU 核发出的读请求,比如 load。wr 是 CPU 核发出的写请求,比如 store。refill 是 L1/L2/L3 miss 后,把下级或其他核的一整条 cache line 填进当前 cache。读 miss 通常会产生 refill;写 miss 要看写策略,典型 write-back + write-allocate 会通过 RFO 取得独占权并 refill,而 no-write-allocate 或 non-temporal store 通常不 refill。writeback 则是脏行被逐出时写回下级,和 refill 方向相反。
结论先说:L2C miss 后“向 LLC 流入”的是请求流;refill 不是这个请求流的一部分,而是数据回来后的“回填”动作。
对 L2C 来说,refill 是:LLC 或内存或其他核返回 cache line 后,把这行填进 L2C。如果 LLC 也 miss,那么 LLC 自己也会先 refill。
L2C 查 tag -> miss
-> 分配 MSHR
-> 若 victim dirty,先 writeback 到 LLC
-> 向 LLC 发请求:rd 或 RFO
-> LLC 查 tag -> hit
-> LLC 返回整条 cache line 给 L2C
-> L2C refill:写入 data array,更新 tag/valid/state
-> 唤醒 L1/CPU 等待的请求
这里:
L2C -> LLCLLC -> L2C所以 refill 的角色是:完成 L2C miss,把 LLC 的数据填进 L2C。
L2C miss
-> 向 LLC 发请求
-> LLC 查 tag -> miss
-> LLC 分配 MSHR
-> LLC 向内存发请求
-> 内存返回 cache line
-> LLC refill:先填 LLC
-> LLC 把该 line 返回给 L2C
-> L2C refill:再填 L2C
-> 唤醒 L1/CPU
这里:
L2C -> LLC -> MemMem -> LLC -> L2C所以 refill 在这里扮演的是:每一级 cache 收到下级数据后,填充自己的动作。
L2C 的 refill 来自 LLC 返回;LLC 的 refill 来自内存返回。
如果是 store 导致 L2C miss:
若 write-allocate:
L2C miss -> 向 LLC 发 RFO
-> 取得独占权
-> LLC 返回 line
-> L2C refill
-> 把 store 数据合并进去
-> 置 dirty
这里 refill 仍然存在,但目的是为了拿到整行再写。
若 no-write-allocate 或 non-temporal store:
L2C miss -> 不 refill L2C
-> 直接写下级
这时 L2C 可能没有 refill。
refill:下级 → 当前 cache,填充数据。writeback:当前 cache → 下级,脏行被逐出时写回。在 L2C miss 流程里,如果选中的 victim 是 dirty:
victim dirty -> writeback 到 LLC
这是 L2C 把脏数据写回 LLC,方向是 L2C -> LLC。
而 refill 是 LLC -> L2C,方向相反。
如果 LLC 发现数据在其他核的 L1/L2 中是 Modified:
L2C miss -> LLC 查询
-> snoop 其他核
-> 其他核直接把数据传给 L2C
-> L2C refill
所以 L2C refill 的数据来源可能是:
但不管来源是谁,对 L2C 来说都叫 refill。
| 阶段 | 请求方向 | 数据方向 | refill 发生位置 |
|---|---|---|---|
| L2C miss 发 LLC | L2C → LLC | 无 | 无 |
| LLC hit | 无 | LLC → L2C | L2C refill |
| LLC miss | LLC → Mem | Mem → LLC | LLC refill |
| LLC 返回 L2C | 无 | LLC → L2C | L2C refill |
| L2C 替换脏行 | L2C → LLC | L2C → LLC | 这是 writeback,不是 refill |
L2C miss 后,向 LLC 流入的是 miss 请求;refill 是 LLC 命中时把数据回填到 L2C,或者 LLC 也 miss 时先回填 LLC、再回填 L2C 的动作。
对每一级 cache 来说,refill 都是“下级数据回来,填进本级 cache”的完成阶段。
如果统计的是数据流量的话,核心事件:无论 Intel 还是 ARM,核心事件都是 L2_CACHE_REFILL(或 L2D_CACHE_REFILL),它统计的是因 L2C Miss 而从外部填充到 L2C 的缓存行(Cache Line)数量,并通过 REFILL_RD 和 REFILL_WR 来区分读/写。
ARM平台的事件命名非常直观,直接区分了访问和填充,以及读和写。
统计读请求流量
使用 L2D_CACHE_RD 事件。它专门统计因内存读操作而导致的L2 Cache访问次数
统计读数据流量 (Refill)
使用 L2D_CACHE_REFILL_RD 事件。这个事件非常精确,它统计的正是由 L2D_CACHE_RD(读访问)所触发的、从核心外部填充到L2的Cache Line数量。ARM的文档明确指出,它统计的是“due to memory read operation”(因内存读操作)而引发的填充
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。