首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >perf_event_open总是返回-1

perf_event_open总是返回-1
EN

Stack Overflow用户
提问于 2016-07-18 17:37:52
回答 4查看 3.5K关注 0票数 6

我运行了以下程序,调用perf_event_open syscall : Linux -桌面3.18.0-20-rpi2 #21-UbuntuSMP抢占Sun 5 01:56:02 UTC 2015 UTC armv7l GNU/Linux

该方案:

代码语言:javascript
运行
复制
#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);
}

它返回错误的打开领导。我检查了fd,看起来它总是返回-1。

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

代码语言:javascript
运行
复制
  #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寄存器。

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

代码语言:javascript
运行
复制
    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

代码语言:javascript
运行
复制
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。我还使用了这个回购,它再次返回fd -1。

我还查看了kallsym,以确保perf_event_open的syscall在那里。

代码语言:javascript
运行
复制
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的输出:

代码语言:javascript
运行
复制
# 
# 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的输出:

代码语言:javascript
运行
复制
root@sama-desktop:/boot# dmesg | grep "perf"
[    0.003891] Initializing cgroup subsys perf_event

下面是设备树的输出:

代码语言:javascript
运行
复制
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。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-07-18 21:14:56

由于缺乏dmesg和sysfs中的相关内容,希望现在应该可以看出,PMU并没有被描述给内核。因此perf事件对您所要求的硬件事件一无所知,因此没有打开它也就不足为奇了。您需要做的是确保内核确实了解PMU,这样驱动程序就应该通过CONFIG_HW_PERF_EVENTS (默认情况下与CONFIG_PERF_EVENTS一起打开,并且在配置中看起来不会被禁用)来获取它--说到驱动程序应该已经内置了,但是它可能值得一次检查。

它看起来像在其3.18内核中的devicetree描述,所以我最好的猜测是,您的董事会可能使用的是旧板文件,而不是FDT。我不太了解Raspberry的具体内容,但从这篇相当详尽的文章 (我可以说直接跳到3.1节)判断,重新配置引导加载程序使用FDT似乎相对简单。

票数 1
EN

Stack Overflow用户

发布于 2017-05-28 22:01:01

对于任何使用Yocto i.MX6构建来回答这个问题的人,比如我的,但与OP不同的是,在dmesg中确实有这样的东西:

代码语言:javascript
运行
复制
hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available

试着在示例代码中注释掉这两行:

代码语言:javascript
运行
复制
pe.exclude_kernel = 1;
pe.exclude_hv = 1;

对我来说,这使得perf_event_open调用成功,我能够收集数据。

票数 1
EN

Stack Overflow用户

发布于 2017-12-02 13:09:32

我刚才和你有同样的问题,现在我的问题是程序的许可,你应该使用更高的权限来运行它,这样一切都是正确的。我使用sudo ./a.out,然后一切都是fine.Maybe --这将有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38442839

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档