如何理解Intel性能计数器评估内存子系统引发的CPU停顿及异常
Xeon Skylake性能计数器缓存停顿读数困惑及解决方案
问题描述
- 在Xeon Skylake芯片上直接访问模型特定寄存器(MSRs)使用Intel性能计数器时,对
CYCLE_ACTIVITY.STALLS_MEM_ANY和CYCLE_ACTIVITY.STALLS_L3_MISS等缓存缺失停顿读数存在理解障碍。 - 运行扫描4GB随机数内存区域(通过查找最大值避免内存访问被编译器优化)的程序时,程序理论上受限于DRAM到L3缓存的传输速度,性能计数器也显示L3存在大量缺失。但
CYCLE_ACTIVITY.STALLS_MEM_ANY(内存子系统未完成加载导致的总停顿周期)数值符合预期的高值,CYCLE_ACTIVITY.STALLS_L3_MISS却极低(不足总停顿的5%),而CYCLE_ACTIVITY.STALLS_L1D_MISS数值很高,接近总停顿。 - 推测:当L1从L2预取失败进而引发L3缺失时,CPU在加载完成前停顿,但L3缺失计数器未统计该情况,因此仅显示L1导致的停顿?
Intel优化手册的困惑
- 原本认为DRAM访问浪费的周期百分比应为
CYCLE_ACTIVITY.STALLS_L3_MISS的变化量除以核心非停顿周期的变化量。 - 但Intel 2024版优化手册22.5.2.3节提供的评估各级缓存对停顿影响的公式基于旧架构的
CYCLE_ACTIVITY.STALLS_XX_PENDING计数器,这类计数器在Skylake中已不存在;且有资料显示Ivy Bridge架构下STALLS_XX_PENDING与XX_MISS定义存在差异,无法理解两者区别,导致无法准确评估DRAM带宽对CPU停顿的影响。
解答
计数器读数差异的核心原因
Skylake架构中,CYCLE_ACTIVITY.STALLS_L1D_MISS与CYCLE_ACTIVITY.STALLS_L3_MISS的统计逻辑完全不同:
STALLS_L1D_MISS统计的是因L1D缓存缺失导致的所有停顿周期——当L1D缺失后,请求会依次进入L2、L3直至DRAM,整个等待过程中只要L1D的请求未完成,该计数器就会持续累加周期,包括后续L2、L3缺失甚至DRAM访问的时间。STALLS_L3_MISS仅统计请求到达L3后,等待DRAM响应的那部分周期,且如果CPU在等待期间能调度其他指令(即使是内存相关指令),这部分周期可能不会被完全统计。
你的推测方向正确:L1D缺失触发的停顿会覆盖后续各级缓存缺失的停顿时间,因为计数器是按“最上层未完成的请求”来统计,而非按每一级缺失单独累加。
正确评估DRAM带宽对停顿的影响(Skylake架构)
由于旧手册中的STALLS_XX_PENDING计数器已被移除,需使用Skylake原生支持的计数器组合:
- 计算DRAM导致的停顿周期:
直接结合L3_MISS_RETIRED.ALL_CAUSES(L3缺失完成的总次数)和平均DRAM访问周期(Skylake中DRAM访问延迟约为60-80ns,对应200-250个核心周期,需结合实际CPU频率调整)。 - 内存绑定百分比的计算公式:
其中%DRAM_Bound = (L3_MISS_RETIRED.ALL_CAUSES * 平均DRAM访问周期) / CPU_CLK_UNHALTED.THREADCPU_CLK_UNHALTED.THREAD是核心未停顿的总周期数,确保分母为CPU实际工作的周期,而非总时钟周期。 - 验证各级缓存的影响:
- 用
MEM_LOAD_UOPS_RETIRED.L1_MISS统计L1缺失次数,结合L1到L2的平均延迟(约4-6个周期)计算L1导致的停顿。 - 用
MEM_LOAD_UOPS_RETIRED.L2_MISS统计L2缺失次数,结合L2到L3的平均延迟(约12-15个周期)计算L2导致的停顿。
- 用
关键注意事项
- Skylake性能计数器统计的是停顿的根源请求,而非每一级停顿的叠加。例如,一次DRAM访问导致的停顿会被归为L1D缺失的停顿,因为L1是最先未命中的层级。
- 务必参考Intel官方《Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 3B: System Programming Guide, Part 2》中Skylake专属的计数器定义,避免套用旧架构的公式。
内容的提问来源于stack exchange,提问作者Coulson Liang
相关产品推荐
相关产品推荐

