gpt4 book ai didi

linux - perf_event_open 总是返回 -1

转载 作者:太空狗 更新时间:2023-10-29 12:12:18 41 4
gpt4 key购买 nike

我运行以下调用 perf_event_open 系统调用的程序:Linux sama-desktop 3.18.0-20-rpi2 #21-Ubuntu SMP PREEMPT Sun Apr 5 01:56:02 UTC 2015 armv7l armv7l armv7l GNU/Linux

程序:

#define _GNU_SOURCE 1

#include <asm/unistd.h>
#include <fcntl.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

long perf_event_open(struct perf_event_attr* event_attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, event_attr, pid, cpu, group_fd, flags);
}

static void perf_event_handler(int signum, siginfo_t* info, void* ucontext) {
if(info->si_code != POLL_HUP) {
// Only POLL_HUP should happen.
exit(EXIT_FAILURE);
}

ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1);
}

int main(int argc, char** argv)
{
// Configure signal handler
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = perf_event_handler;
sa.sa_flags = SA_SIGINFO;

// Setup signal handler
if (sigaction(SIGIO, &sa, NULL) < 0) {
fprintf(stderr,"Error setting up signal handler\n");
perror("sigaction");
exit(EXIT_FAILURE);
}

// Configure perf_event_attr struct
struct perf_event_attr pe;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS; // Count retired hardware instructions
pe.disabled = 1; // Event is initially disabled
pe.sample_type = PERF_SAMPLE_IP;
pe.sample_period = 1000;
pe.exclude_kernel = 1; // excluding events that happen in the kernel-space
pe.exclude_hv = 1; // excluding events that happen in the hypervisor

pid_t pid = 0; // measure the current process/thread
int cpu = -1; // measure on any cpu
int group_fd = -1;
unsigned long flags = 0;

int fd = perf_event_open(&pe, pid, cpu, group_fd, flags);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
perror("perf_event_open");
exit(EXIT_FAILURE);
}
// Setup event handler for overflow signals
fcntl(fd, F_SETFL, O_NONBLOCK|O_ASYNC);
fcntl(fd, F_SETSIG, SIGIO);
fcntl(fd, F_SETOWN, getpid());

ioctl(fd, PERF_EVENT_IOC_RESET, 0); // Reset event counter to 0
ioctl(fd, PERF_EVENT_IOC_REFRESH, 1); //

// Start monitoring

long loopCount = 1000000;
long c = 0;
long i = 0;

// Some sample payload.
for(i = 0; i < loopCount; i++) {
c += 1;
}

// End monitoring

ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); // Disable event

long long counter;
read(fd, &counter, sizeof(long long)); // Read event counter value

printf("Used %lld instructions\n", counter);

close(fd);
}

返回 Error opening leader。我检查了 fd,它看起来总是返回 -1。

我使用了 perf 系统调用手册中的第二个示例,它有同样的问题(错误打开领导者由 fd=-1 触发)。以下是手册中 perf 的示例代码:

  #include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;

ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}

int
main(int argc, char **argv)
{
struct perf_event_attr pe;
long long count;
int fd;

memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;

fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}

ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

printf("Measuring instruction count for this printf\n");

ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(long long));

printf("Used %lld instructions\n", count);

close(fd);
}

我还编写了自己的代码来检查 perf 是否在访问 PMU 寄存器时出现问题。因此,我制作了一个内核模块来启用用户模式访问 PMU 寄存器。

内核模式只执行以下操作:

    asm volatile("mrc p15, 0, %0, c9, c14, 0" :: "r"(1));
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: "r"(1));

然后我尝试运行 perf_event_open

init(void)
{
static struct perf_event_attr attr;
attr.type = PERF_TYPE_HARDWARE;
// attr.config = PERF_COUNT_HW_INSTRUCTIONS;
attr.config = PERF_COUNT_HW_CPU_CYCLES;
fddev = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
printf("The fddev value is %d", fddev);
}

返回 -1。我也用过 this repo fd 再次返回 -1。

我还查看了 kallsyms 以确保 perf_event_open 的系统调用存在。

root@sama-desktop:/home/sama# cat /proc/kallsyms | grep "perf_event_open"
800f3178 T SyS_perf_event_open
800f3178 T sys_perf_event_open

这是/boot/config-3.18.0-20-rpi2 的输出:

# 
# Kernel Performance Events And Counters
#
CONFIG_PERF_EVENTS=y
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
CONFIG_PROFILING=y
CONFIG_TRACEPOINTS=y
CONFIG_OPROFILE=m
CONFIG_HAVE_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_UPROBES=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_KRETPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP_FILTER=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_CC_STACKPROTECTOR=y
# CONFIG_CC_STACKPROTECTOR_NONE is not set
CONFIG_CC_STACKPROTECTOR_REGULAR=y
# CONFIG_CC_STACKPROTECTOR_STRONG is not set
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_OLD_SIGACTION=y

这里是 dmesg 的输出:

root@sama-desktop:/boot# dmesg | grep "perf"
[ 0.003891] Initializing cgroup subsys perf_event

这是设备树的输出:

root@sama-desktop:# ls -la /sys/bus/event_source/devices
total 0
drwxr-xr-x 2 root root 0 jul 18 20:15 .
drwxr-xr-x 4 root root 0 jan 1 1970 ..
lrwxrwxrwx 1 root root 0 jan 1 1970 breakpoint -> ../../../devices/breakpoint
lrwxrwxrwx 1 root root 0 jan 1 1970 software -> ../../../devices/software
lrwxrwxrwx 1 root root 0 jan 1 1970 tracepoint -> ../../../devices/tracepoint

我真的不知道为什么 perf_event_open 返回 -1。

最佳答案

由于 dmesg 和 sysfs 中缺少任何相关内容,现在应该很明显没有向内核描述 PMU。因此 perf events 对您要求的硬件事件一无所知,因此它无法打开它也就不足为奇了。您需要做的是确保内核确实知道 PMU,以便驱动程序选择它 - 所述驱动程序应该已经通过 CONFIG_HW_PERF_EVENTS 内置,默认情况下使用 CONFIG_PERF_EVENTS 和看起来并没有在您的配置中被禁用,但可能值得仔细检查。

看起来像the PMU is described in the devicetree in their 3.18 kernel ,所以我最好的猜测是您的板可能正在使用旧版板文件而不是 FDT 进行引导。我不太了解 Raspberry Pi 的细节,但根据 this fairly exhaustive article 判断(我会说直接跳到第 3.1 节),重新配置引导加载程序以使用 FDT 似乎相对简单。

关于linux - perf_event_open 总是返回 -1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38442839/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com