TLB缺失是否会被PMU计数器统计为CPU前端停顿?
关于AMD Zen2架构下perf PMC读数与TLB缺失、前后端停顿的疑问
我运行了一个小型程序测试不同内存访问模式,通过Linux perf工具得到了令人困惑的PMC(性能监控计数器)读数:
- 访问小内存区域时:大量L1缓存缺失,CPU后端停顿占比高,前端停顿占比可忽略;
- 访问大内存区域(如512个8字节字,间隔1024字节,总大小512KB)时:
perf显示大量L1缺失,但几乎无后端停顿,反而出现大量前端停顿,同时指令/周期比和程序运行速度的下降幅度比仅后端停顿的情况更严重。
程序是由少量mov指令组成的小型循环,所有指令解码应该都已被缓存,核心汇编代码如下:
│ lea _end,%rsi │140:┌─→mov %rbp,%rdx │ │ │ │ lea data_in,%rax │ │ │14a:│ mov (%rax),%rcx <-- 内存访问,即地址计算 │ │memcpy(): 96.31 │ │ mov %rcx,(%rdx) │ │ 1.81 │ │ add $0x400,%rax 0.20 │ │ add $0x400,%rdx <-- 0x400=1024,定义内存访问模式 1.12 │ │ cmp %rsi,%rax 0.57 │ │↑ jne 14a │ │ sub $0x1,%edi │ └──jne 140
按我的理解,所有地址计算(包括TLB缓存相关操作)都发生在CPU后端的内存子系统中,因此内存访问模式的变化应该表现为后端停顿而非前端,这让我困惑。但测得的前端停顿似乎和L1、L2 TLB缺失相关,我想明确以下问题:
- TLB缺失是否会被PMU计为前端停顿?
- 后端是否会因页表遍历耗时过长导致前端停顿?为何PMU计数器不同时报告前后端停顿?是不是后端在计算地址和遍历页表时不被视为“真正停顿”,只是因为遍历耗时太久导致指令流水线被填满,进而停顿前端?
- 虚拟内存结构与前端指令解码器中的微操作缓存(micro-op cache)如何协作?Intel Sandy Bridge的资料提到“微操作缓存采用虚拟寻址,意味着程序地址无需转换即可进行微操作缓存查找”,这是否意味着前端返回的解码指令包含虚拟地址,由后端内存子系统转换为物理地址?因此TLB缺失或其他内存相关问题不会直接影响前端及其微操作缓存?
我的CPU是AMD Zen2架构的Ryzen 5 PRO 4650G。
解答
1. TLB缺失与前端停顿的计数逻辑
在AMD Zen2架构中,TLB缺失本身属于后端内存操作,但部分场景会间接触发前端停顿:
- 当页表遍历需要访问内存时,后端负载单元进入等待状态,若此时后端重排序缓冲区(ROB)被已发出但未完成的指令填满,无法接收新微操作,前端的取指/解码单元就会被迫停止——这种情况会被PMU统计为前端停顿。
- Zen2的PMU对“前端停顿”的定义包含所有无法向后端交付新微操作的场景,并非仅局限于指令取指或解码失败。如果后端因TLB缺失导致流水线阻塞,前端无法继续推送指令,就会被计为前端停顿。
2. 前后端停顿不同时报告的原因
PMU的停顿计数器是按流水线当前无法推进的阶段来统计的:
- 小内存区域访问时,L1缺失直接导致后端执行单元等待数据,阻塞根源在后端,因此统计为后端停顿。
- 大内存区域的跨步访问触发大量TLB缺失时,页表遍历占用后端内存带宽和执行资源,后端ROB被未完成的内存指令填满,前端无法发送新指令——此时流水线阻塞点体现在前端,因此PMU统计为前端停顿,而非后端。
- 这种情况下后端并非没有停顿,只是停顿被前端停顿的统计覆盖,因为PMU优先标记当前流水线无法推进的最前端阻塞点。
3. 微操作缓存与虚拟内存的协作
Zen2的微操作缓存采用虚拟寻址,具体协作逻辑如下:
- 前端取指时,直接通过虚拟地址查找微操作缓存,无需先做地址转换,因此TLB缺失不会直接影响微操作缓存的命中或前端解码流程。
- 微操作中携带的是虚拟地址,地址转换(包括TLB查找、页表遍历)完全由后端的地址生成单元(AGU)完成。TLB缺失是后端的独立操作,不会直接中断前端的指令推送,但当后端阻塞导致ROB填满时,前端会被迫停顿。
内容的提问来源于stack exchange,提问作者xealits
相关产品推荐
相关产品推荐

