2017-05-30 9 views
1

短いCコードスニペットを使用して、1つのプロセスのCPUサイクル数をカウントしようとします。 MWEはcpcycycles.cです。Cで `perf_event`を使用してCPUサイクルをカウントすると、` perf 'と異なる値が返されます

cpucycles.c(重くman page exampleに基づく)

#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; 
} 

long long 
cpu_cycles(pid_t pid, unsigned int microseconds) 
{ 
    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_CPU_CYCLES; 
    pe.disabled = 1; 
    pe.exclude_kernel = 1; 
    pe.exclude_hv = 1; 

    fd = perf_event_open(&pe, pid, -1, -1, 0); 
    if (fd == -1) { 
     return -1; 
    } 

    ioctl(fd, PERF_EVENT_IOC_RESET, 0); 
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); 
    usleep(microseconds); 
    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 
    read(fd, &count, sizeof(long long)); 

    close(fd); 
    return count; 
} 

int main(int argc, char **argv) 
{ 
    printf("CPU cycles: %lld\n", cpu_cycles(atoi(argv[1]), atoi(argv[2]))); 
    return 0; 
} 

次に、私は、それをコンパイルperf_eventアクセス権を設定し、完全なCPU使用率とプロセスを開始し、経由でのCPUサイクルをカウントperfと私のcpucyclesです。

$ gcc -o cpucycles cpucycles.c 
$ echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid 
$ cat /dev/urandom > /dev/null & 
[1] 3214 
$ perf stat -e cycles -p 3214 -x, sleep 1 
3072358388,,cycles,1000577415,100,00,,,, 
$ ./cpucycles 3214 1000000 
CPU cycles: 287953 

明らかに、'perf 'から'3072358388' CPUサイクルだけが、私の3 GHz CPUで正しいです。なぜ私の「巡回隊」はそのような嘲笑を小さな価値観に戻しているのですか?

+0

私の主なポイントは、[the man](http://man7.org/linux/man-pages/man2/perf_event_open.2.html)です:_ 周波数スケーリングの間に起こることに注意してください._ – LPs

+0

残念ながら、いいえ。ガバナーを「パフォーマンス」(CPU周波数スケーリングなし、常に最大周波数を使用)に設定しても、結果は同じです。 – Chickenmarkus

答えて

3

pe.exclude_kernel = 1;を設定すると、プロファイリングのカーネルが除外されます。

フラグを0に設定するだけで大​​きな数字が得られ、1に設定すると小さな数字が表示されることが確認されました。

cat /dev/urandom > /dev/nullは、すべてのCPU時間をカーネル内で消費します。ユーザランドビットは、バッファへの読み込みとそのバッファからの書き込みですが、この場合のすべての重い持ち上げはカーネルによって行われます。

+1

はい、それが問題でした。今は正常に動作しています。ありがとうございました! – Chickenmarkus

関連する問題