perf_event_open无法监控HW_CACHE写入与预取事件求助
解决PERF_TYPE_HW_CACHE写入/预取事件无法注册的问题
问题核心
你遇到的情况是:PERF_TYPE_HW_CACHE类型下,读相关缓存事件可正常注册并统计,但写入、预取类事件无法通过perf_event_open创建,本质原因通常分为三类:CPU硬件不支持目标事件、事件编码或属性配置错误、内核权限/版本限制。
分步排查与修复
1. 先加错误校验,明确失败原因
你的代码未对perf_event_open的返回值做检查,这是排查的第一步。添加错误输出,直接定位问题:
#include <stdio.h> #include <string.h> #include <errno.h> #include <sys/syscall.h> #include <linux/perf_event.h> #include <unistd.h> #include <stdint.h> struct read_format { uint64_t nr; struct { uint64_t value; uint64_t id; } values[]; }; int main() { struct perf_event_attr attr1; memset(&attr1, 0, sizeof(attr1)); // 必须初始化结构体 attr1.size = sizeof(struct perf_event_attr); // 内核会校验该字段,缺失直接失败 attr1.type = PERF_TYPE_HW_CACHE; attr1.config = ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)); attr1.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; int main_fd = syscall(__NR_perf_event_open, &attr1, 0, -1, -1, 0); if (main_fd == -1) { fprintf(stderr, "perf_event_open failed: %s\n", strerror(errno)); return 1; } // 后续逻辑... close(main_fd); return 0; }
如果错误是Invalid argument(EINVAL),基本可以确定是CPU不支持该事件,或者编码错误。
2. 验证系统支持的缓存事件
用perf list命令查看当前CPU实际支持的缓存事件:
perf list cache
输出会列出所有可用的缓存事件,比如Intel CPU可能显示:
L1-dcache-loads [Hardware cache event] L1-dcache-load-misses [Hardware cache event] L1-dcache-stores [Hardware cache event] L1-dcache-store-misses [Hardware cache event]
如果找不到对应写入/预取的事件,说明你的CPU硬件不支持直接统计该类型事件,需要改用raw硬件事件编码。
3. 针对CPU架构调整事件配置
不同CPU架构的缓存事件支持差异极大:
- Intel CPU:写入类事件通常对应
L1-dcache-stores,预取事件大多没有单独统计项,需改用cpu/mem-loads,ldlat=30/P这类raw事件(具体编码需查对应CPU的手册)。 - AMD CPU:部分型号的L1写入事件编码可能需要调整,或需启用特定内核参数。
- ARM CPU:缓存事件的命名和编码逻辑与x86差异很大,需参考对应架构的perf官方文档。
如果硬件不支持标准的PERF_COUNT_HW_CACHE_OP_WRITE/PREFETCH,可以改用raw事件。比如Intel CPU统计L1D写入的示例:
attr1.type = PERF_TYPE_RAW; attr1.config = 0x28; // 对应L1D_STORES,编码需根据CPU型号调整
4. 确认内核版本与权限
- 确保内核版本≥3.10,早期内核对PERF_TYPE_HW_CACHE的支持不完善。
- 运行程序时需要足够权限:要么以root用户运行,要么调整系统参数:
echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid
关键注意点
- 必须初始化
perf_event_attr结构体并设置attr.size,内核会严格校验该字段,缺失会直接返回EINVAL。 - 预取事件的支持非常有限,大部分CPU不会单独统计预取的缓存访问/缺失,只能通过监控预取器相关的raw事件近似统计。
内容的提问来源于stack exchange,提问作者Kron
相关产品推荐
相关产品推荐

