我在我的c profiling应用程序中使用perf_event_open
来利用perf获取事件数据。为了提高性能,我直接阅读硬件寄存器,按照Perf Userspace PMU Hardware Counter Access文档使用mrs
指令直接读取PMU寄存器。
我使用以下代码:
static struct perf_event_attr attr;
attr.type = PERF_TYPE_HARDWARE;
attr.config = PERF_COUNT_HW_CPU_CYCLES;
attr.exclude_kernel = 1;
attr.exclude_hv = 1;
attr.config1 = 3; // user access enabled
int fd = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
// Code where we want to measure performance. At certain points we call read_register_directly()
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
close(fd);
个字符
上面直接读取寄存器的代码在perf配置下可以正常工作。问题是在读了大约25次寄存器后,我得到了一个“非法指令”错误,尽管我不知道为什么。
- 会不会是访问频率限制?
- 或者是ARM安全机制?
- 可能是并发问题?虽然我使用信号量来锁定read_register_directly()以确保一次只读一次,但这个问题仍然存在。
我查看了PMCCNTR_EL0和其他一些资源的ARM文档,但我没有找到任何可以解释这个非法指令错误的东西。
1条答案
按热度按时间kuuvgm7e1#
这最终是由于
perf_event_open
系统调用中传递的属性。进行系统调用的线程能够直接读取寄存器,但其他线程导致“非法指令”错误。有一个
perf_event_attr
标志inherit
,它允许用户分析进程中的所有线程,而不仅仅是perf_event_open
执行的线程。所以在上面的代码中,我添加了两件事来修复代码流:attr.inherit = 1;
个asm volatile("isb;");