2016-07-18 18 views
2

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のperf_event_openは常に-1を返します

プログラム:

#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を返すように見えます。

同じ問題(fd = -1でトリガされたリーダーを開くエラーを開くエラー)を持つperfシステムマニュアルの2番目の例を使用しました。ここでは、手動で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)); 

、その後、私は-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); 
} 

を実行しようとしました。私もthis repoを使用しましたが、fdは-1を返します。

また、kallsymsを見て、perf_event_openのシステムコールがあることを確認しました。

[email protected]:/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の出力である:

[email protected]:/boot# dmesg | grep "perf" 
[ 0.003891] Initializing cgroup subsys perf_event 

とここにありますデバイスツリーの出力:

[email protected]:# 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を返す理由を知らない

+0

devicetreeに記述されているPMUはありますか?あなたは 'hw perfevents:xxx PMUドライバで有効になりました、xカウンターは利用可能です 'のようなものをdmesgのかなり早い段階で見ることができますか? – Notlikethat

+0

いいえ、私はそれを見ていません。しかし私は使用モードからPMUアクセスを可能にするために私自身のドライバを書きました。また、私はこのrepoのドライバ(https://github.com/thoughtpolice/enable_arm_pmu)を使用して、再度PMUを有効にしてからperfを使用します。 dmesg出力で質問を更新しました。 –

+0

x86_64デスクトップで動作する 'perf_event_open()'に問題がありました。私のLinuxデスクトップは仮想マシン(VMware)で動作していたことが判明しました。私はこのコメントを投稿しています。なぜなら、 'perf_event_open()'に問題があったとき、この質問は私が遭遇した問題と最もよくマッチしていたからです。 –

答えて

1

dmesgとsysfsに関連するものがないため、PMUがカーネルに記述されていないことが分かりました。したがって、perfイベントはあなたが求めているハードウェアイベントについて何も知らないので、それを開くことができないのは驚きではありません。あなたがする必要があるのはカーネルにPMUについて知っていることを確認して、ドライバがそれをピックアップするようにします。このドライバはCONFIG_HW_PERF_EVENTS経由で組み込まれている必要があります。CONFIG_PERF_EVENTSでデフォルトでオンになっています。あなたの設定で無効にすることができますが、二重チェックの価値があります。

これはthe PMU is described in the devicetree in their 3.18 kernelのように見えるので、FDTではなく従来のボードファイルを使用してボードが起動している可能性があります。私はラズベリーパイの詳細についてはよく分かりませんが、this fairly exhaustive article(私はセクション3.1に直接スキップします)と判断すると、FDTを使うようにブートローダを再構成するのは比較的簡単です。

0

この質問にYocto iで来る人は誰でも。MX6ビルド、私のような、しかし、OPとは異なりはdmesgの中にこのような何かを持っている:私にとって

pe.exclude_kernel = 1; 
pe.exclude_hv = 1; 

、作られた:

hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available 

は、サンプルコードでは次の2行をコメントアウトしてみてくださいperf_event_openコールが成功し、データを収集することができました。

0

私はちょうどあなたと同じ問題を抱えていましたが、私の問題はプログラムの許可です。すべてのことが正しいように実行するにはより高い権限を使用するべきです。 私はsudo ./a.outを使用していますが、それでも問題ありません。

関連する問題