使用 linux perf 以编程方式测量 L2 相关的原始计数器

问题描述

总体意图

我想测量程序内部特定函数(内部产生许多线程(可能相关?))中表现出的 L2 缓存行为。

我有什么

我尝试过的/做过的

我可以成功运行 this program 以编程方式计算 cpu 周期和页面错误

perf list

但是,我打算计算与 L2 缓存相关的事件,特别是下面显示的事件:

perf stat ...

此类事件出现在 PPR 的表 18(第 172-173 页)中:

enter image description here

根据我从 Linux 内核源代码中的 perf_event_open() documentationlinux/tools/perf/design.txt 中读到的内容,我知道我需要在 #define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #include <string.h> #include <sys/ioctl.h> #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <asm/unistd.h> #include <errno.h> #include <stdint.h> #include <inttypes.h> struct read_format { uint64_t nr; struct { uint64_t value; uint64_t id; } values[]; }; void do_something() { int i; char* ptr; ptr = malloc(100*1024*1024); for (i = 0; i < 100*1024*1024; i++) { ptr[i] = (char) (i & 0xff); // pagefault } free(ptr); } int main(int argc,char* argv[]) { struct perf_event_attr pea; int fd1,fd2; uint64_t id1,id2; uint64_t val1,val2; char buf[4096]; struct read_format* rf = (struct read_format*) buf; int i; memset(&pea,sizeof(struct perf_event_attr)); pea.type = PERF_TYPE_HARDWARE; pea.size = sizeof(struct perf_event_attr); pea.config = PERF_COUNT_HW_cpu_CYCLES; pea.disabled = 1; pea.exclude_kernel = 1; pea.exclude_hv = 1; pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; fd1 = syscall(__NR_perf_event_open,&pea,-1,0); ioctl(fd1,PERF_EVENT_IOC_ID,&id1); memset(&pea,sizeof(struct perf_event_attr)); pea.type = PERF_TYPE_SOFTWARE; pea.size = sizeof(struct perf_event_attr); pea.config = PERF_COUNT_SW_PAGE_FAULTS; pea.disabled = 1; pea.exclude_kernel = 1; pea.exclude_hv = 1; pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; fd2 = syscall(__NR_perf_event_open,fd1 /*!!!*/,0); ioctl(fd2,&id2); ioctl(fd1,PERF_EVENT_IOC_RESET,PERF_IOC_FLAG_GROUP); ioctl(fd1,PERF_EVENT_IOC_ENABLE,PERF_IOC_FLAG_GROUP); do_something(); ioctl(fd1,PERF_EVENT_IOC_disABLE,PERF_IOC_FLAG_GROUP); read(fd1,buf,sizeof(buf)); for (i = 0; i < rf->nr; i++) { if (rf->values[i].id == id1) { val1 = rf->values[i].value; } else if (rf->values[i].id == id2) { val2 = rf->values[i].value; } } printf("cpu cycles: %"PRIu64"\n",val1); printf("page faults: %"PRIu64"\n",val2); return 0; } 成员中指定一个原始事件 $ perf list -v --details | grep -A 4 -e " l2_cache_.*_from_.*_miss" l2_cache_accesses_from_dc_misses [L2 Cache Accesses from L1 Data Cache Misses (including prefetch)] cpu/umask=0xc8,event=0x60/ l2_cache_accesses_from_ic_misses [L2 Cache Accesses from L1 Instruction Cache Misses (including prefetch)] cpu/umask=0x10,event=0x60/ l2_cache_hits_from_dc_misses [L2 Cache Hits from L1 Data Cache Misses] cpu/umask=0x70,event=0x64/ l2_cache_hits_from_ic_misses [L2 Cache Hits from L1 Instruction Cache Misses] cpu/umask=0x6,event=0x64/ l2_cache_misses_from_dc_misses [L2 Cache Misses from L1 Data Cache Misses] cpu/umask=0x8,event=0x64/ l2_cache_misses_from_ic_miss [L2 Cache Misses from L1 Instruction Cache Misses] cpu/umask=0x1,event=0x64/` 结构 PERF_TYPE_RAW 和“为方便起见”使用库 type 根据芯片制造商(在我的情况下为 AMD)提供的事件字符串名称创建配置成员:

如果类型是 PERF_TYPE_RAW,则需要自定义“原始”配置值。 大多数 cpu 支持“通用”未涵盖的事件 事件。这些是实现定义的;请参阅您的 cpu 手册(对于 例如 Intel Volume 3B 文档或 AMD BIOS 和 Kernel 开发者指南)。 libpfm4 库可用于从 建筑手册中原始十六进制值的名称 perf_event_open() 期望在此字段中。

问题

我无法成功使用 libpfm4,尤其是函数 perf_event_attr。当我运行 /perf_examples/evt2raw.c 中的示例代码时,我不断收到消息 libpfm4。当然,我输入了错误的原始计数器字符串表示形式,但是在尝试了几次之后,我不知道应该使用什么。

我检查了一些其他问题,例如 "Using perf to monitor raw event counters",即使他们提供了一些见解,我也无法通过他们解决我的问题。

最后,非常感谢您花时间阅读本文,并可能指导我找到解决方案。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)