问题描述
总体意图
我想测量程序内部特定函数(内部产生许多线程(可能相关?))中表现出的 L2 缓存行为。
我有什么
- Fedora 与 Linux 5.11.14
- AMD 锐龙 Threadripper 3960X。根据{{1}}的{{1}}工具,它是“AMD64 Fam17h Zen2”。
- 来自 AMD 网站的 Processor Programming Reference (PPR) for AMD Family 17h Model 71h,Revision B0 Processors (PPR) 文档。
- Perf 工具已安装并正在运行。我可以跑
check_events
,libpfm4
- 访问我要测量的程序的源代码。
-
The library
libpfm4
已安装并能够运行示例代码。 - 运行机器中的 root 权限。
我尝试过的/做过的
我可以成功运行 this program 以编程方式计算 cpu 周期和页面错误:
perf list
但是,我打算计算与 L2 缓存相关的事件,特别是下面显示的事件:
perf stat ...
此类事件出现在 PPR 的表 18(第 172-173 页)中:
根据我从 Linux 内核源代码中的 perf_event_open() documentation 和 linux/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 (将#修改为@)