Fork me on GitHub
侧边栏

cache 的 refill,wr,rd的区别

结合 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 的结果。

1. CPU cache 路径图

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/wrCPU 核/上游对 cache 的访问请求
  • refillcache miss 后,下级向当前 cache 填充数据
  • 对下级来说,L1 的 refill 往往表现为一次 rd

2. rd 在 CPU cache 中的流程

以 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 字节。
  • 多个 load miss 到同一 line,可以通过 MSHR 合并,只发一次下级请求,一次 refill 服务多个 rd

3. wr 在 CPU cache 中的流程

以 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 的写请求。
  • 写命中通常只改本地 cache,不产生 refill
  • 写 miss 不一定有 refill
    • write-allocate:有 refill,典型是 write-back cache。
    • no-write-allocate:没有 refill
  • 在多核一致性协议里,写 miss 往往需要 RFO,即先拿到独占权,再写。这个 RFO 可能触发其他核 invalidate,并伴随 cache-to-cache transfer 和 refill

4. refill 在 CPU cache 中的流程

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 → 下级,脏行被逐出时发生。
  • refillwriteback 方向相反,不要混淆。
  • refill 通常按 cache line 计,不是按 load/store 大小计。

5. 三者差异:CPU cache 视角

项目 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

6. 典型组合流程

读命中

rd -> L1D hit -> 返回数据

refill

读 miss

rd -> L1D miss -> 向 L2 发 rd -> L2 返回 line -> refill L1D -> 返回 CPU

refill

写命中

wr -> L1D hit -> 写 L1D
write-back:置 dirty
write-through:同时写下级

通常无 refill

写 miss + write-allocate

wr -> L1D miss -> RFO -> 取得独占权 -> refill L1D -> 合并写 -> 置 dirty

refill,而且常伴随一致性动作。

写 miss + no-write-allocate

wr -> L1D miss -> 直接写下级

通常无 L1D refill

脏行被逐出

victim dirty -> writeback 到下级

这是 writeback,不是 refill


7. 多核 CPU cache 中的 refill

多核场景下,L1 miss 不一定只去 L2/内存:

Core0 L1D miss
  -> L2/LLC 查询
  -> 发现 Core1 L1D 有 Modified 数据
  -> snoop Core1
  -> Core1 把数据直接传给 Core0
  -> Core0 refill L1D

所以 refill 的来源可能是:

  • L2
  • L3/LLC
  • 内存
  • 其他 CPU 核的 cache,即 cache-to-cache transfer

写 miss 更复杂,因为要拿所有权:

Core0 store miss
  -> 发 RFO
  -> 其他核 invalidate 对应 line
  -> Core0 取得独占权
  -> refill 或直接合并数据
  -> 写 L1D,置 Modified

8. 一句话总结

在 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 通常不 refillwriteback 则是脏行被逐出时写回下级,和 refill 方向相反。

L2C miss之后,向LLC 流入,refill在这里扮演什么角色

结论先说:L2C miss 后“向 LLC 流入”的是请求流;refill 不是这个请求流的一部分,而是数据回来后的“回填”动作。
对 L2C 来说,refill 是:LLC 或内存或其他核返回 cache line 后,把这行填进 L2C。如果 LLC 也 miss,那么 LLC 自己也会先 refill。


1. 分两种情况看

情况 A:L2C miss,但 LLC hit

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 -> LLC
  • 数据方向:LLC -> L2C
  • refill 位置:只在 L2C
  • LLC 不需要 refill,因为它本来就 hit。

所以 refill 的角色是:完成 L2C miss,把 LLC 的数据填进 L2C。


情况 B:L2C miss,LLC 也 miss

L2C miss
  -> 向 LLC 发请求
  -> LLC 查 tag -> miss
  -> LLC 分配 MSHR
  -> LLC 向内存发请求
  -> 内存返回 cache line
  -> LLC refill:先填 LLC
  -> LLC 把该 line 返回给 L2C
  -> L2C refill:再填 L2C
  -> 唤醒 L1/CPU

这里:

  • 请求方向:L2C -> LLC -> Mem
  • 数据方向:Mem -> LLC -> L2C
  • refill 位置:LLC 先 refill,L2C 后 refill
  • 也就是说,refill 是逐级回填的。

所以 refill 在这里扮演的是:每一级 cache 收到下级数据后,填充自己的动作。
L2C 的 refill 来自 LLC 返回;LLC 的 refill 来自内存返回。


2. 写 miss 时有什么不同

如果是 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。


3. refill 和 writeback 不要混

  • refill:下级 → 当前 cache,填充数据。
  • writeback:当前 cache → 下级,脏行被逐出时写回。

在 L2C miss 流程里,如果选中的 victim 是 dirty:

victim dirty -> writeback 到 LLC

这是 L2C 把脏数据写回 LLC,方向是 L2C -> LLC
而 refill 是 LLC -> L2C,方向相反。


4. 多核情况下 refill 来源可能不是 LLC

如果 LLC 发现数据在其他核的 L1/L2 中是 Modified:

L2C miss -> LLC 查询
  -> snoop 其他核
  -> 其他核直接把数据传给 L2C
  -> L2C refill

所以 L2C refill 的数据来源可能是:

  • LLC
  • 内存
  • 其他 CPU 核的 cache,即 cache-to-cache transfer

但不管来源是谁,对 L2C 来说都叫 refill。


5. 用表总结

阶段 请求方向 数据方向 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

6. 一句话回答

L2C miss 后,向 LLC 流入的是 miss 请求;refill 是 LLC 命中时把数据回填到 L2C,或者 LLC 也 miss 时先回填 LLC、再回填 L2C 的动作。
对每一级 cache 来说,refill 都是“下级数据回来,填进本级 cache”的完成阶段。

统计L2C 写流量

如果统计的是数据流量的话,核心事件:无论 Intel 还是 ARM,核心事件都是 L2_CACHE_REFILL(或 L2D_CACHE_REFILL),它统计的是因 L2C Miss 而从外部填充到 L2C 的缓存行(Cache Line)数量,并通过 REFILL_RD 和 REFILL_WR 来区分读/写。

统计L2C 读流量

ARM平台的事件命名非常直观,直接区分了访问和填充,以及读和写。

  • 统计读请求流量
    使用 L2D_CACHE_RD 事件。它专门统计因内存读操作而导致的L2 Cache访问次数

  • 统计读数据流量 (Refill)
    使用 L2D_CACHE_REFILL_RD 事件。这个事件非常精确,它统计的正是由 L2D_CACHE_RD(读访问)所触发的、从核心外部填充到L2的Cache Line数量。ARM的文档明确指出,它统计的是“due to memory read operation”(因内存读操作)而引发的填充

posted @ 2026-09-19 13:33  yooooooo  阅读(3)  评论(0)    收藏  举报