为何L1缓存缺失远少于L2缓存访问量?缓存行为异常排查
我正在使用perf_event_open工具,通过ARM架构定义的原始性能事件读取L1/L2/L3缓存信息,观察到如下特殊现象:
- L1D misses < L2D accesses
- L2D misses < L3D accesses
- L1D misses < L2D misses
- L2D misses < L3D misses
根据缓存知识,我预期结果完全相反:L1缺失量>L2访问量。此外L1I访问/缺失量加上L1D缺失量仍小于L2D访问量。我猜测L1D替换机制可能导致该差异,但无法解释L2D缓存缺失量小于L3D访问量的情况。是否存在某种硬件缓存机制导致该行为?
我的最终目标是通过捕获全局L3缺失量推导DDR到CPU的带宽,但首先需理解各级缓存的行为逻辑。
可能的硬件机制解释
1. 硬件预取器的影响
现代ARM CPU普遍配备硬件预取器,会主动从下级缓存/内存抓取数据存入上级缓存。这类预取操作会产生L2/L3的访问记录,但并不会对应L1的缺失——比如预取的数据直接进入L2,后续L1访问时直接命中,就不会产生L1 miss,但L2已经有了访问计数。这会直接导致L2 accesses > L1D misses,同理L3预取也会让L3 accesses > L2D misses。
2. 非缓存访问与旁路请求
部分负载会发起非缓存(Non-cacheable)访问,这类请求会直接绕过L1甚至L2,直达L3或DDR。比如DMA操作、内存映射I/O的访问,会直接产生L3 accesses,但不会触发L1/L2的缺失计数。另外,CPU的缓存旁路指令(如ARM的DC ZVA)也会跳过上级缓存,直接访问下级缓存/内存,造成下级访问量大于上级缺失量。
3. 多核缓存一致性操作
在多核系统中,缓存一致性协议(如ARM的CCI/CMN)会产生额外的缓存访问。比如其他核的缓存失效请求、窥探操作,会触发L2/L3的访问,但这些操作并不对应本地核的L1缺失。全局的L3访问统计包含了所有核的一致性流量,而L2 misses可能仅统计本地核的缺失请求,这会导致L3 accesses > L2D misses。
4. 性能事件的定义差异
不同ARM架构对性能事件的定义存在细节差异:
- 部分CPU的
L2D accesses计数包含所有读写操作,而L1D misses仅统计读缺失,写操作可能走Write-Through或Write-Back的特殊路径,不触发L1 miss但会产生L2访问。 - 有些事件统计的是"总请求数"而非"缺失数",比如L3 accesses可能包含命中和缺失的所有请求,而L2D misses仅统计缺失请求,自然会出现L2D misses < L3D accesses。
关于L1D misses < L2D misses的纠正
你的预期(L1缺失> L2缺失)本身不符合缓存层级逻辑,正常的缓存行为应该是L1 misses ≥ L2 misses ≥ L3 misses——因为只有L2缺失才会触发L3访问,L2 misses是L3 misses的上限,反之不可能出现L2 misses < L3 misses。而L1D misses > L2D misses的情况,除了上述预取、一致性因素,还因为L2缓存容量远大于L1,多数L1缺失的数据能在L2命中,所以L2 misses必然小于L1D misses。
DDR带宽推导的建议
如果要通过L3缺失推导DDR带宽,需要:
- 精准选择事件:优先统计"LLC(L3)缺失导致的内存访问"事件,而非所有L3访问。
- 过滤无效流量:部分ARM CPU提供过滤预取、一致性操作的事件选项,确保只统计真正从DDR加载的数据。
- 结合硬件参数:L3缺失通常对应缓存行大小的传输,需用「缓存行大小 × L3缺失数 × 时钟周期」换算实际带宽。
内容的提问来源于stack exchange,提问作者Kron

